mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Rename TaskState to DownloadState
PiperOrigin-RevId: 225145311
This commit is contained in:
parent
230a798f23
commit
4bf42bd2ad
8 changed files with 205 additions and 217 deletions
|
|
@ -27,6 +27,7 @@
|
||||||
([#5169](https://github.com/google/ExoPlayer/issues/5169)).
|
([#5169](https://github.com/google/ExoPlayer/issues/5169)).
|
||||||
* DownloadManager:
|
* DownloadManager:
|
||||||
* Create only one task for all DownloadActions for the same content.
|
* Create only one task for all DownloadActions for the same content.
|
||||||
|
* Rename TaskState to DownloadState.
|
||||||
|
|
||||||
### 2.9.2 ###
|
### 2.9.2 ###
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ package com.google.android.exoplayer2.demo;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import com.google.android.exoplayer2.offline.DownloadManager;
|
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.DownloadService;
|
||||||
import com.google.android.exoplayer2.scheduler.PlatformScheduler;
|
import com.google.android.exoplayer2.scheduler.PlatformScheduler;
|
||||||
import com.google.android.exoplayer2.ui.DownloadNotificationUtil;
|
import com.google.android.exoplayer2.ui.DownloadNotificationUtil;
|
||||||
|
|
@ -50,40 +50,40 @@ public class DemoDownloadService extends DownloadService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Notification getForegroundNotification(TaskState[] taskStates) {
|
protected Notification getForegroundNotification(DownloadState[] downloadStates) {
|
||||||
return DownloadNotificationUtil.buildProgressNotification(
|
return DownloadNotificationUtil.buildProgressNotification(
|
||||||
/* context= */ this,
|
/* context= */ this,
|
||||||
R.drawable.ic_download,
|
R.drawable.ic_download,
|
||||||
CHANNEL_ID,
|
CHANNEL_ID,
|
||||||
/* contentIntent= */ null,
|
/* contentIntent= */ null,
|
||||||
/* message= */ null,
|
/* message= */ null,
|
||||||
taskStates);
|
downloadStates);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onTaskStateChanged(TaskState taskState) {
|
protected void onDownloadStateChanged(DownloadState downloadState) {
|
||||||
if (taskState.action.isRemoveAction) {
|
if (downloadState.action.isRemoveAction) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Notification notification = null;
|
Notification notification = null;
|
||||||
if (taskState.state == TaskState.STATE_COMPLETED) {
|
if (downloadState.state == DownloadState.STATE_COMPLETED) {
|
||||||
notification =
|
notification =
|
||||||
DownloadNotificationUtil.buildDownloadCompletedNotification(
|
DownloadNotificationUtil.buildDownloadCompletedNotification(
|
||||||
/* context= */ this,
|
/* context= */ this,
|
||||||
R.drawable.ic_download_done,
|
R.drawable.ic_download_done,
|
||||||
CHANNEL_ID,
|
CHANNEL_ID,
|
||||||
/* contentIntent= */ null,
|
/* contentIntent= */ null,
|
||||||
Util.fromUtf8Bytes(taskState.action.data));
|
Util.fromUtf8Bytes(downloadState.action.data));
|
||||||
} else if (taskState.state == TaskState.STATE_FAILED) {
|
} else if (downloadState.state == DownloadState.STATE_FAILED) {
|
||||||
notification =
|
notification =
|
||||||
DownloadNotificationUtil.buildDownloadFailedNotification(
|
DownloadNotificationUtil.buildDownloadFailedNotification(
|
||||||
/* context= */ this,
|
/* context= */ this,
|
||||||
R.drawable.ic_download_done,
|
R.drawable.ic_download_done,
|
||||||
CHANNEL_ID,
|
CHANNEL_ID,
|
||||||
/* contentIntent= */ null,
|
/* 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);
|
NotificationUtil.setNotification(this, notificationId, notification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ import com.google.android.exoplayer2.offline.ActionFile;
|
||||||
import com.google.android.exoplayer2.offline.DownloadAction;
|
import com.google.android.exoplayer2.offline.DownloadAction;
|
||||||
import com.google.android.exoplayer2.offline.DownloadHelper;
|
import com.google.android.exoplayer2.offline.DownloadHelper;
|
||||||
import com.google.android.exoplayer2.offline.DownloadManager;
|
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.DownloadService;
|
||||||
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;
|
||||||
|
|
@ -144,11 +144,11 @@ public class DownloadTracker implements DownloadManager.Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTaskStateChanged(DownloadManager downloadManager, TaskState taskState) {
|
public void onDownloadStateChanged(DownloadManager downloadManager, DownloadState downloadState) {
|
||||||
DownloadAction action = taskState.action;
|
DownloadAction action = downloadState.action;
|
||||||
Uri uri = action.uri;
|
Uri uri = action.uri;
|
||||||
if ((action.isRemoveAction && taskState.state == TaskState.STATE_COMPLETED)
|
if ((action.isRemoveAction && downloadState.state == DownloadState.STATE_COMPLETED)
|
||||||
|| (!action.isRemoveAction && taskState.state == TaskState.STATE_FAILED)) {
|
|| (!action.isRemoveAction && downloadState.state == DownloadState.STATE_FAILED)) {
|
||||||
// A download has been removed, or has failed. Stop tracking it.
|
// A download has been removed, or has failed. Stop tracking it.
|
||||||
if (trackedDownloadStates.remove(uri) != null) {
|
if (trackedDownloadStates.remove(uri) != null) {
|
||||||
handleTrackedDownloadStatesChanged();
|
handleTrackedDownloadStatesChanged();
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.offline;
|
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.DownloadState.STATE_COMPLETED;
|
||||||
import static com.google.android.exoplayer2.offline.DownloadManager.TaskState.STATE_FAILED;
|
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_FAILED;
|
||||||
import static com.google.android.exoplayer2.offline.DownloadManager.TaskState.STATE_QUEUED;
|
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_QUEUED;
|
||||||
import static com.google.android.exoplayer2.offline.DownloadManager.TaskState.STATE_STARTED;
|
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_STARTED;
|
||||||
|
|
||||||
import android.os.ConditionVariable;
|
import android.os.ConditionVariable;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
|
@ -58,41 +58,41 @@ public final class DownloadManager {
|
||||||
*/
|
*/
|
||||||
void onInitialized(DownloadManager 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 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.
|
* @param downloadManager The reporting instance.
|
||||||
*/
|
*/
|
||||||
void onIdle(DownloadManager downloadManager);
|
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;
|
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;
|
public static final int DEFAULT_MIN_RETRY_COUNT = 5;
|
||||||
|
|
||||||
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 maxActiveDownloadTasks;
|
private final int maxActiveDownloads;
|
||||||
private final int minRetryCount;
|
private final int minRetryCount;
|
||||||
private final ActionFile actionFile;
|
private final ActionFile actionFile;
|
||||||
private final DownloaderFactory downloaderFactory;
|
private final DownloaderFactory downloaderFactory;
|
||||||
private final ArrayList<Task> tasks;
|
private final ArrayList<Download> downloads;
|
||||||
private final ArrayList<Task> activeDownloadTasks;
|
private final ArrayList<Download> activeDownloads;
|
||||||
private final Handler handler;
|
private final Handler handler;
|
||||||
private final HandlerThread fileIOThread;
|
private final HandlerThread fileIOThread;
|
||||||
private final Handler fileIOHandler;
|
private final Handler fileIOHandler;
|
||||||
private final CopyOnWriteArraySet<Listener> listeners;
|
private final CopyOnWriteArraySet<Listener> listeners;
|
||||||
|
|
||||||
private int nextTaskId;
|
private int nextDownloadId;
|
||||||
private boolean initialized;
|
private boolean initialized;
|
||||||
private boolean released;
|
private boolean released;
|
||||||
private boolean downloadsStopped;
|
private boolean downloadsStopped;
|
||||||
|
|
@ -113,8 +113,8 @@ public final class DownloadManager {
|
||||||
*
|
*
|
||||||
* @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 download tasks.
|
* @param maxSimultaneousDownloads The maximum number of simultaneous downloads.
|
||||||
* @param minRetryCount The minimum number of times a task must be retried before failing.
|
* @param minRetryCount The minimum number of times a download must be retried before failing.
|
||||||
*/
|
*/
|
||||||
public DownloadManager(
|
public DownloadManager(
|
||||||
File actionFile,
|
File actionFile,
|
||||||
|
|
@ -123,12 +123,12 @@ public final class DownloadManager {
|
||||||
int minRetryCount) {
|
int minRetryCount) {
|
||||||
this.actionFile = new ActionFile(actionFile);
|
this.actionFile = new ActionFile(actionFile);
|
||||||
this.downloaderFactory = downloaderFactory;
|
this.downloaderFactory = downloaderFactory;
|
||||||
this.maxActiveDownloadTasks = maxSimultaneousDownloads;
|
this.maxActiveDownloads = maxSimultaneousDownloads;
|
||||||
this.minRetryCount = minRetryCount;
|
this.minRetryCount = minRetryCount;
|
||||||
this.downloadsStopped = true;
|
this.downloadsStopped = true;
|
||||||
|
|
||||||
tasks = new ArrayList<>();
|
downloads = new ArrayList<>();
|
||||||
activeDownloadTasks = new ArrayList<>();
|
activeDownloads = new ArrayList<>();
|
||||||
|
|
||||||
Looper looper = Looper.myLooper();
|
Looper looper = Looper.myLooper();
|
||||||
if (looper == null) {
|
if (looper == null) {
|
||||||
|
|
@ -164,23 +164,23 @@ public final class DownloadManager {
|
||||||
listeners.remove(listener);
|
listeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Starts the download tasks. */
|
/** Starts the downloads. */
|
||||||
public void startDownloads() {
|
public void startDownloads() {
|
||||||
Assertions.checkState(!released);
|
Assertions.checkState(!released);
|
||||||
if (downloadsStopped) {
|
if (downloadsStopped) {
|
||||||
downloadsStopped = false;
|
downloadsStopped = false;
|
||||||
maybeStartTasks();
|
maybeStartDownloads();
|
||||||
logd("Downloads are started");
|
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() {
|
public void stopDownloads() {
|
||||||
Assertions.checkState(!released);
|
Assertions.checkState(!released);
|
||||||
if (!downloadsStopped) {
|
if (!downloadsStopped) {
|
||||||
downloadsStopped = true;
|
downloadsStopped = true;
|
||||||
for (int i = 0; i < activeDownloadTasks.size(); i++) {
|
for (int i = 0; i < activeDownloads.size(); i++) {
|
||||||
activeDownloadTasks.get(i).stop();
|
activeDownloads.get(i).stop();
|
||||||
}
|
}
|
||||||
logd("Downloads are stopping");
|
logd("Downloads are stopping");
|
||||||
}
|
}
|
||||||
|
|
@ -189,64 +189,50 @@ public final class DownloadManager {
|
||||||
/**
|
/**
|
||||||
* Handles the given action.
|
* 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.
|
* @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) {
|
public int handleAction(DownloadAction action) {
|
||||||
Assertions.checkState(!released);
|
Assertions.checkState(!released);
|
||||||
Task task = addTaskForAction(action);
|
Download download = getDownloadForAction(action);
|
||||||
if (initialized) {
|
if (initialized) {
|
||||||
saveActions();
|
saveActions();
|
||||||
maybeStartTasks();
|
maybeStartDownloads();
|
||||||
if (task.state == STATE_QUEUED) {
|
if (download.state == STATE_QUEUED) {
|
||||||
// Task did not change out of its initial state, and so its initial state won't have been
|
// Download did not change out of its initial state, and so its initial state won't have
|
||||||
|
// been
|
||||||
// reported to listeners. Do so now.
|
// reported to listeners. Do so now.
|
||||||
notifyListenersTaskStateChange(task);
|
notifyListenersDownloadStateChange(download);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return task.id;
|
return download.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the number of tasks. */
|
/** Returns the number of downloads. */
|
||||||
public int getTaskCount() {
|
|
||||||
Assertions.checkState(!released);
|
|
||||||
return tasks.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the number of download tasks. */
|
|
||||||
public int getDownloadCount() {
|
public int getDownloadCount() {
|
||||||
int count = 0;
|
Assertions.checkState(!released);
|
||||||
for (int i = 0; i < tasks.size(); i++) {
|
return downloads.size();
|
||||||
for (DownloadAction action : tasks.get(i).actionQueue) {
|
|
||||||
if (!action.isRemoveAction) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the state of a task, or null if no such task exists */
|
/** Returns the state of a download, or null if no such download exists */
|
||||||
public @Nullable TaskState getTaskState(int taskId) {
|
@Nullable
|
||||||
|
public DownloadState getDownloadState(int downloadId) {
|
||||||
Assertions.checkState(!released);
|
Assertions.checkState(!released);
|
||||||
for (int i = 0; i < tasks.size(); i++) {
|
for (int i = 0; i < downloads.size(); i++) {
|
||||||
Task task = tasks.get(i);
|
Download download = downloads.get(i);
|
||||||
if (task.id == taskId) {
|
if (download.id == downloadId) {
|
||||||
return task.getTaskState();
|
return download.getDownloadState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the states of all current tasks. */
|
/** Returns the states of all current downloads. */
|
||||||
public TaskState[] getAllTaskStates() {
|
public DownloadState[] getAllDownloadStates() {
|
||||||
Assertions.checkState(!released);
|
Assertions.checkState(!released);
|
||||||
TaskState[] states = new TaskState[tasks.size()];
|
DownloadState[] states = new DownloadState[downloads.size()];
|
||||||
for (int i = 0; i < states.length; i++) {
|
for (int i = 0; i < states.length; i++) {
|
||||||
states[i] = tasks.get(i).getTaskState();
|
states[i] = downloads.get(i).getDownloadState();
|
||||||
}
|
}
|
||||||
return states;
|
return states;
|
||||||
}
|
}
|
||||||
|
|
@ -257,14 +243,14 @@ public final class DownloadManager {
|
||||||
return initialized;
|
return initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns whether there are no active tasks. */
|
/** Returns whether there are no active downloads. */
|
||||||
public boolean isIdle() {
|
public boolean isIdle() {
|
||||||
Assertions.checkState(!released);
|
Assertions.checkState(!released);
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < tasks.size(); i++) {
|
for (int i = 0; i < downloads.size(); i++) {
|
||||||
if (tasks.get(i).isStarted()) {
|
if (downloads.get(i).isStarted()) {
|
||||||
return false;
|
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
|
* Stops all of the downloads and releases resources. If the action file isn't up to date, waits
|
||||||
* the changes to be written. The manager must not be accessed after this method has been called.
|
* for the changes to be written. The manager must not be accessed after this method has been
|
||||||
|
* called.
|
||||||
*/
|
*/
|
||||||
public void release() {
|
public void release() {
|
||||||
if (released) {
|
if (released) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
released = true;
|
released = true;
|
||||||
for (int i = 0; i < tasks.size(); i++) {
|
for (int i = 0; i < downloads.size(); i++) {
|
||||||
tasks.get(i).stop();
|
downloads.get(i).stop();
|
||||||
}
|
}
|
||||||
final ConditionVariable fileIOFinishedCondition = new ConditionVariable();
|
final ConditionVariable fileIOFinishedCondition = new ConditionVariable();
|
||||||
fileIOHandler.post(fileIOFinishedCondition::open);
|
fileIOHandler.post(fileIOFinishedCondition::open);
|
||||||
|
|
@ -290,47 +277,47 @@ public final class DownloadManager {
|
||||||
logd("Released");
|
logd("Released");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task addTaskForAction(DownloadAction action) {
|
private Download getDownloadForAction(DownloadAction action) {
|
||||||
for (int i = 0; i < tasks.size(); i++) {
|
for (int i = 0; i < downloads.size(); i++) {
|
||||||
Task task = tasks.get(i);
|
Download download = downloads.get(i);
|
||||||
if (task.action.isSameMedia(action)) {
|
if (download.action.isSameMedia(action)) {
|
||||||
task.addAction(action);
|
download.addAction(action);
|
||||||
logd("Action is added to existing task", task);
|
logd("Action is added to existing download", download);
|
||||||
return task;
|
return download;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Task task = new Task(nextTaskId++, this, downloaderFactory, action, minRetryCount);
|
Download download =
|
||||||
tasks.add(task);
|
new Download(nextDownloadId++, this, downloaderFactory, action, minRetryCount);
|
||||||
logd("Task is added", task);
|
downloads.add(download);
|
||||||
return task;
|
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>
|
* <ul>
|
||||||
* <li>It hasn't started yet.
|
* <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>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
private void maybeStartTasks() {
|
private void maybeStartDownloads() {
|
||||||
if (!initialized || released) {
|
if (!initialized || released) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean skipDownloadActions = downloadsStopped
|
boolean skipDownloads = downloadsStopped || activeDownloads.size() == maxActiveDownloads;
|
||||||
|| activeDownloadTasks.size() == maxActiveDownloadTasks;
|
for (int i = 0; i < downloads.size(); i++) {
|
||||||
for (int i = 0; i < tasks.size(); i++) {
|
Download download = downloads.get(i);
|
||||||
Task task = tasks.get(i);
|
if (!download.canStart()) {
|
||||||
if (!task.canStart()) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
boolean isRemoveAction = task.action.isRemoveAction;
|
boolean isRemoveAction = download.action.isRemoveAction;
|
||||||
if (isRemoveAction || !skipDownloadActions) {
|
if (isRemoveAction || !skipDownloads) {
|
||||||
task.start();
|
download.start();
|
||||||
if (!isRemoveAction) {
|
if (!isRemoveAction) {
|
||||||
activeDownloadTasks.add(task);
|
activeDownloads.add(download);
|
||||||
skipDownloadActions = activeDownloadTasks.size() == maxActiveDownloadTasks;
|
skipDownloads = activeDownloads.size() == maxActiveDownloads;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -346,30 +333,30 @@ public final class DownloadManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onTaskStateChange(Task task) {
|
private void onDownloadStateChange(Download download) {
|
||||||
if (released) {
|
if (released) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean stopped = !task.isStarted();
|
boolean stopped = !download.isStarted();
|
||||||
if (stopped) {
|
if (stopped) {
|
||||||
activeDownloadTasks.remove(task);
|
activeDownloads.remove(download);
|
||||||
}
|
}
|
||||||
notifyListenersTaskStateChange(task);
|
notifyListenersDownloadStateChange(download);
|
||||||
if (task.isFinished()) {
|
if (download.isFinished()) {
|
||||||
tasks.remove(task);
|
downloads.remove(download);
|
||||||
saveActions();
|
saveActions();
|
||||||
}
|
}
|
||||||
if (stopped) {
|
if (stopped) {
|
||||||
maybeStartTasks();
|
maybeStartDownloads();
|
||||||
maybeNotifyListenersIdle();
|
maybeNotifyListenersIdle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyListenersTaskStateChange(Task task) {
|
private void notifyListenersDownloadStateChange(Download download) {
|
||||||
logd("Task state is changed", task);
|
logd("Download state is changed", download);
|
||||||
TaskState taskState = task.getTaskState();
|
DownloadState downloadState = download.getDownloadState();
|
||||||
for (Listener listener : listeners) {
|
for (Listener listener : listeners) {
|
||||||
listener.onTaskStateChanged(this, taskState);
|
listener.onDownloadStateChanged(this, downloadState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -390,27 +377,27 @@ public final class DownloadManager {
|
||||||
if (released) {
|
if (released) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<Task> pendingTasks = new ArrayList<>(tasks);
|
List<Download> pendingDownloads = new ArrayList<>(downloads);
|
||||||
tasks.clear();
|
downloads.clear();
|
||||||
for (DownloadAction action : actions) {
|
for (DownloadAction action : actions) {
|
||||||
addTaskForAction(action);
|
getDownloadForAction(action);
|
||||||
}
|
}
|
||||||
logd("Tasks are created.");
|
logd("Downloads are created.");
|
||||||
initialized = true;
|
initialized = true;
|
||||||
for (Listener listener : listeners) {
|
for (Listener listener : listeners) {
|
||||||
listener.onInitialized(DownloadManager.this);
|
listener.onInitialized(DownloadManager.this);
|
||||||
}
|
}
|
||||||
if (!pendingTasks.isEmpty()) {
|
if (!pendingDownloads.isEmpty()) {
|
||||||
tasks.addAll(pendingTasks);
|
downloads.addAll(pendingDownloads);
|
||||||
saveActions();
|
saveActions();
|
||||||
}
|
}
|
||||||
maybeStartTasks();
|
maybeStartDownloads();
|
||||||
for (int i = 0; i < tasks.size(); i++) {
|
for (int i = 0; i < downloads.size(); i++) {
|
||||||
Task task = tasks.get(i);
|
Download download = downloads.get(i);
|
||||||
if (task.state == STATE_QUEUED) {
|
if (download.state == STATE_QUEUED) {
|
||||||
// Task did not change out of its initial state, and so its initial state
|
// Download did not change out of its initial state, and so its initial state
|
||||||
// won't have been reported to listeners. Do so now.
|
// won't have been reported to listeners. Do so now.
|
||||||
notifyListenersTaskStateChange(task);
|
notifyListenersDownloadStateChange(download);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -421,9 +408,9 @@ public final class DownloadManager {
|
||||||
if (released) {
|
if (released) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ArrayList<DownloadAction> actions = new ArrayList<>(tasks.size());
|
ArrayList<DownloadAction> actions = new ArrayList<>(downloads.size());
|
||||||
for (int i = 0; i < tasks.size(); i++) {
|
for (int i = 0; i < downloads.size(); i++) {
|
||||||
actions.addAll(tasks.get(i).actionQueue);
|
actions.addAll(downloads.get(i).actionQueue);
|
||||||
}
|
}
|
||||||
final DownloadAction[] actionsArray = actions.toArray(new DownloadAction[0]);
|
final DownloadAction[] actionsArray = actions.toArray(new DownloadAction[0]);
|
||||||
fileIOHandler.post(
|
fileIOHandler.post(
|
||||||
|
|
@ -443,16 +430,16 @@ public final class DownloadManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void logd(String message, Task task) {
|
private static void logd(String message, Download download) {
|
||||||
logd(message + ": " + task);
|
logd(message + ": " + download);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Represents state of a task. */
|
/** Represents state of a download. */
|
||||||
public static final class TaskState {
|
public static final class DownloadState {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Task states. One of {@link #STATE_QUEUED}, {@link #STATE_STARTED}, {@link #STATE_COMPLETED}
|
* Download states. One of {@link #STATE_QUEUED}, {@link #STATE_STARTED}, {@link
|
||||||
* or {@link #STATE_FAILED}.
|
* #STATE_COMPLETED} or {@link #STATE_FAILED}.
|
||||||
*
|
*
|
||||||
* <p>Transition diagram:
|
* <p>Transition diagram:
|
||||||
*
|
*
|
||||||
|
|
@ -465,13 +452,13 @@ public final class DownloadManager {
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef({STATE_QUEUED, STATE_STARTED, STATE_COMPLETED, STATE_FAILED})
|
@IntDef({STATE_QUEUED, STATE_STARTED, STATE_COMPLETED, STATE_FAILED})
|
||||||
public @interface State {}
|
public @interface State {}
|
||||||
/** The task is waiting to be started. */
|
/** The download is waiting to be started. */
|
||||||
public static final int STATE_QUEUED = 0;
|
public static final int STATE_QUEUED = 0;
|
||||||
/** The task is currently started. */
|
/** The download is currently started. */
|
||||||
public static final int STATE_STARTED = 1;
|
public static final int STATE_STARTED = 1;
|
||||||
/** The task completed. */
|
/** The download completed. */
|
||||||
public static final int STATE_COMPLETED = 2;
|
public static final int STATE_COMPLETED = 2;
|
||||||
/** The task failed. */
|
/** The download failed. */
|
||||||
public static final int STATE_FAILED = 3;
|
public static final int STATE_FAILED = 3;
|
||||||
|
|
||||||
/** Returns the state string for the given state value. */
|
/** Returns the state string for the given state value. */
|
||||||
|
|
@ -490,16 +477,15 @@ public final class DownloadManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The unique task id. */
|
/** The unique download id. */
|
||||||
public final int taskId;
|
public final int id;
|
||||||
/** The action being executed. */
|
/** The action being executed. */
|
||||||
public final DownloadAction action;
|
public final DownloadAction action;
|
||||||
/** The state of the task. */
|
/** The state of the download. */
|
||||||
public final @State int state;
|
public final @State int state;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The estimated download percentage, or {@link C#PERCENTAGE_UNSET} if no estimate is available
|
* The estimated download percentage, or {@link C#PERCENTAGE_UNSET} if no estimate is available.
|
||||||
* or if this is a removal task.
|
|
||||||
*/
|
*/
|
||||||
public final float downloadPercentage;
|
public final float downloadPercentage;
|
||||||
/** The total number of downloaded bytes. */
|
/** 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. */
|
/** If {@link #state} is {@link #STATE_FAILED} then this is the cause, otherwise null. */
|
||||||
@Nullable public final Throwable error;
|
@Nullable public final Throwable error;
|
||||||
|
|
||||||
private TaskState(
|
private DownloadState(
|
||||||
int taskId,
|
int id,
|
||||||
DownloadAction action,
|
DownloadAction action,
|
||||||
@State int state,
|
@State int state,
|
||||||
float downloadPercentage,
|
float downloadPercentage,
|
||||||
long downloadedBytes,
|
long downloadedBytes,
|
||||||
long totalBytes,
|
long totalBytes,
|
||||||
@Nullable Throwable error) {
|
@Nullable Throwable error) {
|
||||||
this.taskId = taskId;
|
this.id = id;
|
||||||
this.action = action;
|
this.action = action;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.downloadPercentage = downloadPercentage;
|
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. */
|
/** Target states for the download thread. */
|
||||||
@Documented
|
@Documented
|
||||||
|
|
@ -543,10 +529,10 @@ public final class DownloadManager {
|
||||||
private final int minRetryCount;
|
private final int minRetryCount;
|
||||||
private final ArrayDeque<DownloadAction> actionQueue;
|
private final ArrayDeque<DownloadAction> actionQueue;
|
||||||
private DownloadAction action;
|
private DownloadAction action;
|
||||||
/** The current state of the task. */
|
/** The current state of the download. */
|
||||||
@TaskState.State private int state;
|
@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.
|
* thread stops.
|
||||||
*/
|
*/
|
||||||
@TargetState private volatile int targetState;
|
@TargetState private volatile int targetState;
|
||||||
|
|
@ -555,7 +541,7 @@ public final class DownloadManager {
|
||||||
@MonotonicNonNull private DownloadThread downloadThread;
|
@MonotonicNonNull private DownloadThread downloadThread;
|
||||||
@MonotonicNonNull private Throwable error;
|
@MonotonicNonNull private Throwable error;
|
||||||
|
|
||||||
private Task(
|
private Download(
|
||||||
int id,
|
int id,
|
||||||
DownloadManager downloadManager,
|
DownloadManager downloadManager,
|
||||||
DownloaderFactory downloaderFactory,
|
DownloaderFactory downloaderFactory,
|
||||||
|
|
@ -586,11 +572,11 @@ public final class DownloadManager {
|
||||||
} else {
|
} else {
|
||||||
Assertions.checkState(state == STATE_QUEUED);
|
Assertions.checkState(state == STATE_QUEUED);
|
||||||
action = updatedAction;
|
action = updatedAction;
|
||||||
downloadManager.onTaskStateChange(this);
|
downloadManager.onDownloadStateChange(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TaskState getTaskState() {
|
public DownloadState getDownloadState() {
|
||||||
float downloadPercentage = C.PERCENTAGE_UNSET;
|
float downloadPercentage = C.PERCENTAGE_UNSET;
|
||||||
long downloadedBytes = 0;
|
long downloadedBytes = 0;
|
||||||
long totalBytes = C.LENGTH_UNSET;
|
long totalBytes = C.LENGTH_UNSET;
|
||||||
|
|
@ -599,16 +585,16 @@ public final class DownloadManager {
|
||||||
downloadedBytes = downloader.getDownloadedBytes();
|
downloadedBytes = downloader.getDownloadedBytes();
|
||||||
totalBytes = downloader.getTotalBytes();
|
totalBytes = downloader.getTotalBytes();
|
||||||
}
|
}
|
||||||
return new TaskState(
|
return new DownloadState(
|
||||||
id, action, state, downloadPercentage, downloadedBytes, totalBytes, error);
|
id, action, state, downloadPercentage, downloadedBytes, totalBytes, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns whether the task is finished. */
|
/** Returns whether the download is finished. */
|
||||||
public boolean isFinished() {
|
public boolean isFinished() {
|
||||||
return state == STATE_FAILED || state == STATE_COMPLETED;
|
return state == STATE_FAILED || state == STATE_COMPLETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns whether the task is started. */
|
/** Returns whether the download is started. */
|
||||||
public boolean isStarted() {
|
public boolean isStarted() {
|
||||||
return state == STATE_STARTED;
|
return state == STATE_STARTED;
|
||||||
}
|
}
|
||||||
|
|
@ -619,9 +605,9 @@ public final class DownloadManager {
|
||||||
+ ' '
|
+ ' '
|
||||||
+ (action.isRemoveAction ? "remove" : "download")
|
+ (action.isRemoveAction ? "remove" : "download")
|
||||||
+ ' '
|
+ ' '
|
||||||
+ TaskState.getStateString(state)
|
+ DownloadState.getStateString(state)
|
||||||
+ ' '
|
+ ' '
|
||||||
+ TaskState.getStateString(targetState);
|
+ DownloadState.getStateString(targetState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canStart() {
|
public boolean canStart() {
|
||||||
|
|
@ -637,7 +623,7 @@ public final class DownloadManager {
|
||||||
downloadThread =
|
downloadThread =
|
||||||
new DownloadThread(
|
new DownloadThread(
|
||||||
this, downloader, action.isRemoveAction, minRetryCount, downloadManager.handler);
|
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.
|
// Internal methods running on the main thread.
|
||||||
|
|
||||||
private void stopDownloadThread() {
|
private void stopDownloadThread() {
|
||||||
this.targetState = TaskState.STATE_QUEUED;
|
this.targetState = DownloadState.STATE_QUEUED;
|
||||||
Assertions.checkNotNull(downloadThread).cancel();
|
Assertions.checkNotNull(downloadThread).cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -664,19 +650,19 @@ public final class DownloadManager {
|
||||||
} else {
|
} else {
|
||||||
actionQueue.remove();
|
actionQueue.remove();
|
||||||
if (!actionQueue.isEmpty()) {
|
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;
|
state = STATE_QUEUED;
|
||||||
action = actionQueue.peek();
|
action = actionQueue.peek();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
downloadManager.onTaskStateChange(this);
|
downloadManager.onDownloadStateChange(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class DownloadThread implements Runnable {
|
private static class DownloadThread implements Runnable {
|
||||||
|
|
||||||
private final Task task;
|
private final Download download;
|
||||||
private final Downloader downloader;
|
private final Downloader downloader;
|
||||||
private final boolean remove;
|
private final boolean remove;
|
||||||
private final int minRetryCount;
|
private final int minRetryCount;
|
||||||
|
|
@ -685,12 +671,12 @@ public final class DownloadManager {
|
||||||
private volatile boolean isCanceled;
|
private volatile boolean isCanceled;
|
||||||
|
|
||||||
private DownloadThread(
|
private DownloadThread(
|
||||||
Task task,
|
Download download,
|
||||||
Downloader downloader,
|
Downloader downloader,
|
||||||
boolean remove,
|
boolean remove,
|
||||||
int minRetryCount,
|
int minRetryCount,
|
||||||
Handler callbackHandler) {
|
Handler callbackHandler) {
|
||||||
this.task = task;
|
this.download = download;
|
||||||
this.downloader = downloader;
|
this.downloader = downloader;
|
||||||
this.remove = remove;
|
this.remove = remove;
|
||||||
this.minRetryCount = minRetryCount;
|
this.minRetryCount = minRetryCount;
|
||||||
|
|
@ -709,7 +695,7 @@ public final class DownloadManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
logd("Task is started", task);
|
logd("Download is started", download);
|
||||||
Throwable error = null;
|
Throwable error = null;
|
||||||
try {
|
try {
|
||||||
if (remove) {
|
if (remove) {
|
||||||
|
|
@ -725,14 +711,14 @@ public final class DownloadManager {
|
||||||
if (!isCanceled) {
|
if (!isCanceled) {
|
||||||
long downloadedBytes = downloader.getDownloadedBytes();
|
long downloadedBytes = downloader.getDownloadedBytes();
|
||||||
if (downloadedBytes != errorPosition) {
|
if (downloadedBytes != errorPosition) {
|
||||||
logd("Reset error count. downloadedBytes = " + downloadedBytes, task);
|
logd("Reset error count. downloadedBytes = " + downloadedBytes, download);
|
||||||
errorPosition = downloadedBytes;
|
errorPosition = downloadedBytes;
|
||||||
errorCount = 0;
|
errorCount = 0;
|
||||||
}
|
}
|
||||||
if (++errorCount > minRetryCount) {
|
if (++errorCount > minRetryCount) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
logd("Download error. Retry " + errorCount, task);
|
logd("Download error. Retry " + errorCount, download);
|
||||||
Thread.sleep(getRetryDelayMillis(errorCount));
|
Thread.sleep(getRetryDelayMillis(errorCount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -742,7 +728,7 @@ public final class DownloadManager {
|
||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
final Throwable finalError = error;
|
final Throwable finalError = error;
|
||||||
callbackHandler.post(() -> task.onDownloadThreadStopped(isCanceled ? null : finalError));
|
callbackHandler.post(() -> download.onDownloadThreadStopped(isCanceled ? null : finalError));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getRetryDelayMillis(int errorCount) {
|
private int getRetryDelayMillis(int errorCount) {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import android.os.IBinder;
|
||||||
import android.os.Looper;
|
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.offline.DownloadManager.TaskState;
|
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState;
|
||||||
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.RequirementsWatcher;
|
||||||
import com.google.android.exoplayer2.scheduler.Scheduler;
|
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 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 tasks (and the
|
// Keep the requirements helper for each DownloadService as long as there are downloads (and the
|
||||||
// process is running). This allows tasks to resume when there's no scheduler. It may also allow
|
// process is running). This allows downloads to resume when there's no scheduler. It may also
|
||||||
// tasks the resume more quickly than when relying on the scheduler alone.
|
// allow downloads the resume more quickly than when relying on the scheduler alone.
|
||||||
private static final HashMap<Class<? extends DownloadService>, RequirementsHelper>
|
private static final HashMap<Class<? extends DownloadService>, RequirementsHelper>
|
||||||
requirementsHelpers = new HashMap<>();
|
requirementsHelpers = new HashMap<>();
|
||||||
private static final Requirements DEFAULT_REQUIREMENTS =
|
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
|
* <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
|
* {@value #FOREGROUND_NOTIFICATION_ID_NONE}) the service runs in the foreground with {@link
|
||||||
* #DEFAULT_FOREGROUND_NOTIFICATION_UPDATE_INTERVAL}. In that case {@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
|
* @param foregroundNotificationId The notification id for the foreground notification, or {@link
|
||||||
* #FOREGROUND_NOTIFICATION_ID_NONE} (value {@value #FOREGROUND_NOTIFICATION_ID_NONE})
|
* #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
|
* 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
|
* @param foregroundNotificationId The notification id for the foreground notification, must not
|
||||||
* be 0.
|
* be 0.
|
||||||
|
|
@ -128,7 +128,7 @@ public abstract class DownloadService extends Service {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a DownloadService which will run in the foreground. {@link
|
* 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
|
* @param foregroundNotificationId The notification id for the foreground notification. Must not
|
||||||
* be 0.
|
* 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>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
|
* <p>This method is called when there is a download state change and periodically while there are
|
||||||
* active tasks. The periodic update interval can be set using {@link #DownloadService(int,
|
* active downloads. The periodic update interval can be set using {@link #DownloadService(int,
|
||||||
* long)}.
|
* long)}.
|
||||||
*
|
*
|
||||||
* <p>On API level 26 and above, this method may also be called just before the service stops,
|
* <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.
|
* 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.
|
* @return The foreground notification to display.
|
||||||
*/
|
*/
|
||||||
protected Notification getForegroundNotification(TaskState[] taskStates) {
|
protected Notification getForegroundNotification(DownloadState[] downloadStates) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
getClass().getName()
|
getClass().getName()
|
||||||
+ " is started in the foreground but getForegroundNotification() is not implemented.");
|
+ " 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.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -428,10 +428,11 @@ public abstract class DownloadService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTaskStateChanged(DownloadManager downloadManager, TaskState taskState) {
|
public void onDownloadStateChanged(
|
||||||
DownloadService.this.onTaskStateChanged(taskState);
|
DownloadManager downloadManager, DownloadState downloadState) {
|
||||||
|
DownloadService.this.onDownloadStateChanged(downloadState);
|
||||||
if (foregroundNotificationUpdater != null) {
|
if (foregroundNotificationUpdater != null) {
|
||||||
if (taskState.state == TaskState.STATE_STARTED) {
|
if (downloadState.state == DownloadState.STATE_STARTED) {
|
||||||
foregroundNotificationUpdater.startPeriodicUpdates();
|
foregroundNotificationUpdater.startPeriodicUpdates();
|
||||||
} else {
|
} else {
|
||||||
foregroundNotificationUpdater.update();
|
foregroundNotificationUpdater.update();
|
||||||
|
|
@ -471,8 +472,8 @@ public abstract class DownloadService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update() {
|
public void update() {
|
||||||
TaskState[] taskStates = downloadManager.getAllTaskStates();
|
DownloadState[] downloadStates = downloadManager.getAllDownloadStates();
|
||||||
startForeground(notificationId, getForegroundNotification(taskStates));
|
startForeground(notificationId, getForegroundNotification(downloadStates));
|
||||||
notificationDisplayed = true;
|
notificationDisplayed = true;
|
||||||
if (periodicUpdatesStarted) {
|
if (periodicUpdatesStarted) {
|
||||||
handler.removeCallbacks(this);
|
handler.removeCallbacks(this);
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ 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.DownloadManager.TaskState;
|
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState;
|
||||||
import com.google.android.exoplayer2.offline.DownloadManager.TaskState.State;
|
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState.State;
|
||||||
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;
|
||||||
|
|
@ -371,11 +371,11 @@ public class DownloadManagerTest {
|
||||||
TaskWrapper task2 = new DownloadRunner(uri2).postDownloadAction().getTask();
|
TaskWrapper task2 = new DownloadRunner(uri2).postDownloadAction().getTask();
|
||||||
TaskWrapper task3 = new DownloadRunner(uri3).postRemoveAction().getTask();
|
TaskWrapper task3 = new DownloadRunner(uri3).postRemoveAction().getTask();
|
||||||
|
|
||||||
TaskState[] states = downloadManager.getAllTaskStates();
|
DownloadState[] states = downloadManager.getAllDownloadStates();
|
||||||
|
|
||||||
assertThat(states).hasLength(3);
|
assertThat(states).hasLength(3);
|
||||||
int[] taskIds = {task1.taskId, task2.taskId, task3.taskId};
|
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);
|
assertThat(stateTaskIds).isEqualTo(taskIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -522,19 +522,19 @@ public class DownloadManagerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskWrapper assertStarted() throws InterruptedException {
|
private TaskWrapper assertStarted() throws InterruptedException {
|
||||||
return assertState(TaskState.STATE_STARTED);
|
return assertState(DownloadState.STATE_STARTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskWrapper assertCompleted() {
|
private TaskWrapper assertCompleted() {
|
||||||
return assertState(TaskState.STATE_COMPLETED);
|
return assertState(DownloadState.STATE_COMPLETED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskWrapper assertFailed() {
|
private TaskWrapper assertFailed() {
|
||||||
return assertState(TaskState.STATE_FAILED);
|
return assertState(DownloadState.STATE_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskWrapper assertQueued() {
|
private TaskWrapper assertQueued() {
|
||||||
return assertState(TaskState.STATE_QUEUED);
|
return assertState(DownloadState.STATE_QUEUED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskWrapper assertState(@State int expectedState) {
|
private TaskWrapper assertState(@State int expectedState) {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import com.google.android.exoplayer2.C;
|
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. */
|
/** Helper for creating download notifications. */
|
||||||
public final class DownloadNotificationUtil {
|
public final class DownloadNotificationUtil {
|
||||||
|
|
@ -33,7 +33,7 @@ public final class DownloadNotificationUtil {
|
||||||
private 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 context A context for accessing resources.
|
||||||
* @param smallIcon A small icon for the notification.
|
* @param smallIcon A small icon for the notification.
|
||||||
|
|
@ -41,7 +41,7 @@ public final class DownloadNotificationUtil {
|
||||||
* above.
|
* above.
|
||||||
* @param contentIntent An optional content intent to send when the notification is clicked.
|
* @param contentIntent An optional content intent to send when the notification is clicked.
|
||||||
* @param message An optional message to display on the notification.
|
* @param message An optional message to display on the notification.
|
||||||
* @param taskStates The task states.
|
* @param downloadStates The download states.
|
||||||
* @return The notification.
|
* @return The notification.
|
||||||
*/
|
*/
|
||||||
public static Notification buildProgressNotification(
|
public static Notification buildProgressNotification(
|
||||||
|
|
@ -50,28 +50,28 @@ public final class DownloadNotificationUtil {
|
||||||
String channelId,
|
String channelId,
|
||||||
@Nullable PendingIntent contentIntent,
|
@Nullable PendingIntent contentIntent,
|
||||||
@Nullable String message,
|
@Nullable String message,
|
||||||
TaskState[] taskStates) {
|
DownloadState[] downloadStates) {
|
||||||
float totalPercentage = 0;
|
float totalPercentage = 0;
|
||||||
int downloadTaskCount = 0;
|
int downloadTaskCount = 0;
|
||||||
boolean allDownloadPercentagesUnknown = true;
|
boolean allDownloadPercentagesUnknown = true;
|
||||||
boolean haveDownloadedBytes = false;
|
boolean haveDownloadedBytes = false;
|
||||||
boolean haveDownloadTasks = false;
|
boolean haveDownloadTasks = false;
|
||||||
boolean haveRemoveTasks = false;
|
boolean haveRemoveTasks = false;
|
||||||
for (TaskState taskState : taskStates) {
|
for (DownloadState downloadState : downloadStates) {
|
||||||
if (taskState.state != TaskState.STATE_STARTED
|
if (downloadState.state != DownloadState.STATE_STARTED
|
||||||
&& taskState.state != TaskState.STATE_COMPLETED) {
|
&& downloadState.state != DownloadState.STATE_COMPLETED) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (taskState.action.isRemoveAction) {
|
if (downloadState.action.isRemoveAction) {
|
||||||
haveRemoveTasks = true;
|
haveRemoveTasks = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
haveDownloadTasks = true;
|
haveDownloadTasks = true;
|
||||||
if (taskState.downloadPercentage != C.PERCENTAGE_UNSET) {
|
if (downloadState.downloadPercentage != C.PERCENTAGE_UNSET) {
|
||||||
allDownloadPercentagesUnknown = false;
|
allDownloadPercentagesUnknown = false;
|
||||||
totalPercentage += taskState.downloadPercentage;
|
totalPercentage += downloadState.downloadPercentage;
|
||||||
}
|
}
|
||||||
haveDownloadedBytes |= taskState.downloadedBytes > 0;
|
haveDownloadedBytes |= downloadState.downloadedBytes > 0;
|
||||||
downloadTaskCount++;
|
downloadTaskCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package com.google.android.exoplayer2.testutil;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.offline.DownloadManager;
|
import com.google.android.exoplayer2.offline.DownloadManager;
|
||||||
|
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState;
|
||||||
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;
|
||||||
|
|
@ -56,12 +57,11 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTaskStateChanged(
|
public void onDownloadStateChanged(DownloadManager downloadManager, DownloadState downloadState) {
|
||||||
DownloadManager downloadManager, DownloadManager.TaskState taskState) {
|
if (downloadState.state == DownloadState.STATE_FAILED && downloadError == null) {
|
||||||
if (taskState.state == DownloadManager.TaskState.STATE_FAILED && downloadError == null) {
|
downloadError = downloadState.error;
|
||||||
downloadError = taskState.error;
|
|
||||||
}
|
}
|
||||||
getStateQueue(taskState.taskId).add(taskState.state);
|
getStateQueue(downloadState.id).add(downloadState.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue