mirror of
https://github.com/samsonjs/media.git
synced 2026-04-06 11:25:46 +00:00
Fix stopping downloads
- Changed startDownloads/stopDownloads back to their previous behavior of starting and stopping all downloads at the manager level. - Made setManualStopReason methods for the new case of setting a manual stop reason or some or all downloads. - Added plumbing to specify an initial manual stop reason when adding a new download, without also overwriting the manual stop reasons of all other preexisting downloads. Using the value is left as a TODO pending a bit of further cleanup that'll make it easier. PiperOrigin-RevId: 242891688
This commit is contained in:
parent
68993f233d
commit
9779d71a1d
5 changed files with 198 additions and 180 deletions
|
|
@ -46,7 +46,7 @@ public final class Download {
|
|||
// Important: These constants are persisted into DownloadIndex. Do not change them.
|
||||
/** The download is waiting to be started. */
|
||||
public static final int STATE_QUEUED = 0;
|
||||
/** The download is stopped. */
|
||||
/** The download is manually stopped for the reason specified by {@link #manualStopReason}. */
|
||||
public static final int STATE_STOPPED = 1;
|
||||
/** The download is currently started. */
|
||||
public static final int STATE_DOWNLOADING = 2;
|
||||
|
|
@ -71,8 +71,6 @@ public final class Download {
|
|||
|
||||
/** The download isn't manually stopped. */
|
||||
public static final int MANUAL_STOP_REASON_NONE = 0;
|
||||
/** The download is manually stopped but a reason isn't specified. */
|
||||
public static final int MANUAL_STOP_REASON_UNDEFINED = Integer.MAX_VALUE;
|
||||
|
||||
/** Returns the state string for the given state value. */
|
||||
public static String getStateString(@State int state) {
|
||||
|
|
@ -122,7 +120,7 @@ public final class Download {
|
|||
* #FAILURE_REASON_NONE}.
|
||||
*/
|
||||
@FailureReason public final int failureReason;
|
||||
/** The manual stop reason. */
|
||||
/** The reason the download is manually stopped, or {@link #MANUAL_STOP_REASON_NONE}. */
|
||||
public final int manualStopReason;
|
||||
|
||||
/*package*/ CachingCounters counters;
|
||||
|
|
@ -232,7 +230,7 @@ public final class Download {
|
|||
this.counters = counters;
|
||||
}
|
||||
|
||||
private static int getNextState(int currentState, boolean canStart) {
|
||||
private static int getNextState(@State int currentState, boolean canStart) {
|
||||
if (currentState == STATE_REMOVING || currentState == STATE_RESTARTING) {
|
||||
return STATE_RESTARTING;
|
||||
} else if (canStart) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package com.google.android.exoplayer2.offline;
|
|||
import static com.google.android.exoplayer2.offline.Download.FAILURE_REASON_NONE;
|
||||
import static com.google.android.exoplayer2.offline.Download.FAILURE_REASON_UNKNOWN;
|
||||
import static com.google.android.exoplayer2.offline.Download.MANUAL_STOP_REASON_NONE;
|
||||
import static com.google.android.exoplayer2.offline.Download.MANUAL_STOP_REASON_UNDEFINED;
|
||||
import static com.google.android.exoplayer2.offline.Download.STATE_COMPLETED;
|
||||
import static com.google.android.exoplayer2.offline.Download.STATE_DOWNLOADING;
|
||||
import static com.google.android.exoplayer2.offline.Download.STATE_FAILED;
|
||||
|
|
@ -53,7 +52,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
/**
|
||||
* Manages multiple stream download and remove requests.
|
||||
* Manages downloads.
|
||||
*
|
||||
* <p>Normally a download manager should be accessed via a {@link DownloadService}. When a download
|
||||
* manager is used directly instead, downloads will be initially stopped and so must be started by
|
||||
* calling {@link #startDownloads()}.
|
||||
*
|
||||
* <p>A download manager instance must be accessed only from the thread that created it, unless that
|
||||
* thread does not have a {@link Looper}. In that case, it must be accessed only from the
|
||||
|
|
@ -122,12 +125,13 @@ public final class DownloadManager {
|
|||
|
||||
// Messages posted to the background handler.
|
||||
private static final int MSG_INITIALIZE = 0;
|
||||
private static final int MSG_ADD_DOWNLOAD = 1;
|
||||
private static final int MSG_REMOVE_DOWNLOAD = 2;
|
||||
private static final int MSG_SET_DOWNLOADS_STARTED = 1;
|
||||
private static final int MSG_SET_NOT_MET_REQUIREMENTS = 2;
|
||||
private static final int MSG_SET_MANUAL_STOP_REASON = 3;
|
||||
private static final int MSG_SET_NOT_MET_REQUIREMENTS = 4;
|
||||
private static final int MSG_DOWNLOAD_THREAD_STOPPED = 5;
|
||||
private static final int MSG_RELEASE = 6;
|
||||
private static final int MSG_ADD_DOWNLOAD = 4;
|
||||
private static final int MSG_REMOVE_DOWNLOAD = 5;
|
||||
private static final int MSG_DOWNLOAD_THREAD_STOPPED = 6;
|
||||
private static final int MSG_RELEASE = 7;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
|
|
@ -174,7 +178,7 @@ public final class DownloadManager {
|
|||
|
||||
// Mutable fields that are accessed on the internal thread.
|
||||
@Requirements.RequirementFlags private int notMetRequirements;
|
||||
private int manualStopReason;
|
||||
private boolean downloadsStarted;
|
||||
private int simultaneousDownloads;
|
||||
|
||||
/**
|
||||
|
|
@ -244,7 +248,6 @@ public final class DownloadManager {
|
|||
this.maxSimultaneousDownloads = maxSimultaneousDownloads;
|
||||
this.minRetryCount = minRetryCount;
|
||||
|
||||
manualStopReason = MANUAL_STOP_REASON_UNDEFINED;
|
||||
downloadInternals = new ArrayList<>();
|
||||
downloads = new ArrayList<>();
|
||||
activeDownloads = new HashMap<>();
|
||||
|
|
@ -331,63 +334,37 @@ public final class DownloadManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Clears manual stop reason of all downloads. Downloads are started if the requirements are met.
|
||||
* Starts all downloads except those that are manually stopped (i.e. have a non-zero {@link
|
||||
* Download#manualStopReason}).
|
||||
*/
|
||||
public void startDownloads() {
|
||||
postSetManualStopReason(/* id= */ null, MANUAL_STOP_REASON_NONE);
|
||||
pendingMessages++;
|
||||
internalHandler
|
||||
.obtainMessage(MSG_SET_DOWNLOADS_STARTED, /* downloadsStarted */ 1, /* unused */ 0)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
/** Signals all downloads to stop. Call {@link #startDownloads()} to let them to be started. */
|
||||
/** Stops all downloads. */
|
||||
public void stopDownloads() {
|
||||
stopDownloads(MANUAL_STOP_REASON_UNDEFINED);
|
||||
pendingMessages++;
|
||||
internalHandler
|
||||
.obtainMessage(MSG_SET_DOWNLOADS_STARTED, /* downloadsStarted */ 0, /* unused */ 0)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a manual stop reason for all downloads.
|
||||
* Sets the manual stop reason for one or all downloads. To clear the manual stop reason, pass
|
||||
* {@link Download#MANUAL_STOP_REASON_NONE}.
|
||||
*
|
||||
* @param manualStopReason An application defined stop reason. Value {@value
|
||||
* Download#MANUAL_STOP_REASON_NONE} is not allowed and value {@value
|
||||
* Download#MANUAL_STOP_REASON_UNDEFINED} is reserved for {@link
|
||||
* Download#MANUAL_STOP_REASON_UNDEFINED}.
|
||||
* @param id The content id of the download to update, or {@code null} to set the manual stop
|
||||
* reason for all downloads.
|
||||
* @param manualStopReason The manual stop reason, or {@link Download#MANUAL_STOP_REASON_NONE}.
|
||||
*/
|
||||
public void stopDownloads(int manualStopReason) {
|
||||
Assertions.checkArgument(manualStopReason != MANUAL_STOP_REASON_NONE);
|
||||
postSetManualStopReason(/* id= */ null, manualStopReason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears manual stop reason of the download with the {@code id}. Download is started if the
|
||||
* requirements are met.
|
||||
*
|
||||
* @param id The unique content id of the download to be started.
|
||||
*/
|
||||
public void startDownload(String id) {
|
||||
postSetManualStopReason(id, MANUAL_STOP_REASON_NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals the download with the {@code id} to stop. Call {@link #startDownload(String)} to let it
|
||||
* to be started.
|
||||
*
|
||||
* @param id The unique content id of the download to be stopped.
|
||||
*/
|
||||
public void stopDownload(String id) {
|
||||
stopDownload(id, MANUAL_STOP_REASON_UNDEFINED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals the download with the {@code id} to stop. Call {@link #startDownload(String)} to let it
|
||||
* to be started.
|
||||
*
|
||||
* @param id The unique content id of the download to be stopped.
|
||||
* @param manualStopReason An application defined stop reason. Value {@value
|
||||
* Download#MANUAL_STOP_REASON_NONE} is not allowed and value {@value
|
||||
* Download#MANUAL_STOP_REASON_UNDEFINED} is reserved for {@link
|
||||
* Download#MANUAL_STOP_REASON_UNDEFINED}.
|
||||
*/
|
||||
public void stopDownload(String id, int manualStopReason) {
|
||||
Assertions.checkArgument(manualStopReason != MANUAL_STOP_REASON_NONE);
|
||||
postSetManualStopReason(id, manualStopReason);
|
||||
public void setManualStopReason(@Nullable String id, int manualStopReason) {
|
||||
pendingMessages++;
|
||||
internalHandler
|
||||
.obtainMessage(MSG_SET_MANUAL_STOP_REASON, manualStopReason, /* unused */ 0, id)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -396,8 +373,21 @@ public final class DownloadManager {
|
|||
* @param action The download action.
|
||||
*/
|
||||
public void addDownload(DownloadAction action) {
|
||||
addDownload(action, Download.MANUAL_STOP_REASON_NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a download defined by the given action and with the specified manual stop reason.
|
||||
*
|
||||
* @param action The download action.
|
||||
* @param manualStopReason An initial manual stop reason for the download, or {@link
|
||||
* Download#MANUAL_STOP_REASON_NONE} if the download should be started.
|
||||
*/
|
||||
public void addDownload(DownloadAction action, int manualStopReason) {
|
||||
pendingMessages++;
|
||||
internalHandler.obtainMessage(MSG_ADD_DOWNLOAD, action).sendToTarget();
|
||||
internalHandler
|
||||
.obtainMessage(MSG_ADD_DOWNLOAD, manualStopReason, /* unused */ 0, action)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -442,13 +432,6 @@ public final class DownloadManager {
|
|||
}
|
||||
}
|
||||
|
||||
private void postSetManualStopReason(@Nullable String id, int manualStopReason) {
|
||||
pendingMessages++;
|
||||
internalHandler
|
||||
.obtainMessage(MSG_SET_MANUAL_STOP_REASON, manualStopReason, /* unused */ 0, id)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
private void onRequirementsStateChanged(
|
||||
RequirementsWatcher requirementsWatcher,
|
||||
@Requirements.RequirementFlags int notMetRequirements) {
|
||||
|
|
@ -551,27 +534,32 @@ public final class DownloadManager {
|
|||
int notMetRequirements = message.arg1;
|
||||
initializeInternal(notMetRequirements);
|
||||
break;
|
||||
case MSG_ADD_DOWNLOAD:
|
||||
DownloadAction action = (DownloadAction) message.obj;
|
||||
addDownloadInternal(action);
|
||||
break;
|
||||
case MSG_REMOVE_DOWNLOAD:
|
||||
String id = (String) message.obj;
|
||||
removeDownloadInternal(id);
|
||||
break;
|
||||
case MSG_SET_MANUAL_STOP_REASON:
|
||||
id = (String) message.obj;
|
||||
int manualStopReason = message.arg1;
|
||||
setManualStopReasonInternal(id, manualStopReason);
|
||||
case MSG_SET_DOWNLOADS_STARTED:
|
||||
boolean downloadsStarted = message.arg1 != 0;
|
||||
setDownloadsStartedInternal(downloadsStarted);
|
||||
break;
|
||||
case MSG_SET_NOT_MET_REQUIREMENTS:
|
||||
notMetRequirements = message.arg1;
|
||||
setNotMetRequirementsInternal(notMetRequirements);
|
||||
break;
|
||||
case MSG_SET_MANUAL_STOP_REASON:
|
||||
String id = (String) message.obj;
|
||||
int manualStopReason = message.arg1;
|
||||
setManualStopReasonInternal(id, manualStopReason);
|
||||
break;
|
||||
case MSG_ADD_DOWNLOAD:
|
||||
DownloadAction action = (DownloadAction) message.obj;
|
||||
manualStopReason = message.arg1;
|
||||
addDownloadInternal(action, manualStopReason);
|
||||
break;
|
||||
case MSG_REMOVE_DOWNLOAD:
|
||||
id = (String) message.obj;
|
||||
removeDownloadInternal(id);
|
||||
break;
|
||||
case MSG_DOWNLOAD_THREAD_STOPPED:
|
||||
DownloadThread downloadThread = (DownloadThread) message.obj;
|
||||
onDownloadThreadStoppedInternal(downloadThread);
|
||||
processedExternalMessage = false;
|
||||
processedExternalMessage = false; // This message is posted internally.
|
||||
break;
|
||||
case MSG_RELEASE:
|
||||
releaseInternal();
|
||||
|
|
@ -594,7 +582,6 @@ public final class DownloadManager {
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
this.manualStopReason = manualStopReason;
|
||||
for (int i = 0; i < downloadInternals.size(); i++) {
|
||||
downloadInternals.get(i).setManualStopReason(manualStopReason);
|
||||
}
|
||||
|
|
@ -610,7 +597,8 @@ public final class DownloadManager {
|
|||
}
|
||||
}
|
||||
|
||||
private void addDownloadInternal(DownloadAction action) {
|
||||
// TODO: Use manualStopReason.
|
||||
private void addDownloadInternal(DownloadAction action, int manualStopReason) {
|
||||
DownloadInternal downloadInternal = getDownload(action.id);
|
||||
if (downloadInternal != null) {
|
||||
downloadInternal.addAction(action);
|
||||
|
|
@ -621,7 +609,7 @@ public final class DownloadManager {
|
|||
download = new Download(action);
|
||||
logd("Download state is created for " + action.id);
|
||||
} else {
|
||||
download = download.copyWithMergedAction(action, /* canStart= */ notMetRequirements == 0);
|
||||
download = download.copyWithMergedAction(action, /* canStart= */ canStartDownloads());
|
||||
logd("Download state is loaded for " + action.id);
|
||||
}
|
||||
addDownloadForState(download);
|
||||
|
|
@ -666,6 +654,16 @@ public final class DownloadManager {
|
|||
mainHandler.obtainMessage(MSG_DOWNLOAD_REMOVED, download).sendToTarget();
|
||||
}
|
||||
|
||||
private void setDownloadsStartedInternal(boolean downloadsStarted) {
|
||||
if (this.downloadsStarted == downloadsStarted) {
|
||||
return;
|
||||
}
|
||||
this.downloadsStarted = downloadsStarted;
|
||||
for (int i = 0; i < downloadInternals.size(); i++) {
|
||||
downloadInternals.get(i).updateStopState();
|
||||
}
|
||||
}
|
||||
|
||||
private void setNotMetRequirementsInternal(
|
||||
@Requirements.RequirementFlags int notMetRequirements) {
|
||||
if (this.notMetRequirements == notMetRequirements) {
|
||||
|
|
@ -674,7 +672,7 @@ public final class DownloadManager {
|
|||
this.notMetRequirements = notMetRequirements;
|
||||
logdFlags("Not met requirements are changed", notMetRequirements);
|
||||
for (int i = 0; i < downloadInternals.size(); i++) {
|
||||
downloadInternals.get(i).setNotMetRequirements(notMetRequirements);
|
||||
downloadInternals.get(i).updateStopState();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -682,7 +680,7 @@ public final class DownloadManager {
|
|||
private DownloadInternal getDownload(String id) {
|
||||
for (int i = 0; i < downloadInternals.size(); i++) {
|
||||
DownloadInternal downloadInternal = downloadInternals.get(i);
|
||||
if (downloadInternal.getId().equals(id)) {
|
||||
if (downloadInternal.download.action.id.equals(id)) {
|
||||
return downloadInternal;
|
||||
}
|
||||
}
|
||||
|
|
@ -723,13 +721,16 @@ public final class DownloadManager {
|
|||
}
|
||||
|
||||
private void addDownloadForState(Download download) {
|
||||
DownloadInternal downloadInternal =
|
||||
new DownloadInternal(this, download, notMetRequirements, manualStopReason);
|
||||
DownloadInternal downloadInternal = new DownloadInternal(this, download);
|
||||
downloadInternals.add(downloadInternal);
|
||||
logd("Download is added", downloadInternal);
|
||||
downloadInternal.initialize();
|
||||
}
|
||||
|
||||
private boolean canStartDownloads() {
|
||||
return downloadsStarted && notMetRequirements == 0;
|
||||
}
|
||||
|
||||
private static void logd(String message) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, message);
|
||||
|
|
@ -814,32 +815,24 @@ public final class DownloadManager {
|
|||
private final DownloadManager downloadManager;
|
||||
|
||||
private Download download;
|
||||
@Download.State private int state;
|
||||
@MonotonicNonNull @Download.FailureReason private int failureReason;
|
||||
@Requirements.RequirementFlags private int notMetRequirements;
|
||||
|
||||
// TODO: Get rid of these and use download directly.
|
||||
@Download.State private int state;
|
||||
private int manualStopReason;
|
||||
|
||||
private DownloadInternal(
|
||||
DownloadManager downloadManager,
|
||||
Download download,
|
||||
@Requirements.RequirementFlags int notMetRequirements,
|
||||
int manualStopReason) {
|
||||
private DownloadInternal(DownloadManager downloadManager, Download download) {
|
||||
this.downloadManager = downloadManager;
|
||||
this.download = download;
|
||||
this.notMetRequirements = notMetRequirements;
|
||||
this.manualStopReason = manualStopReason;
|
||||
manualStopReason = download.manualStopReason;
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
initialize(download.state);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return download.action.id;
|
||||
}
|
||||
|
||||
public void addAction(DownloadAction newAction) {
|
||||
download = download.copyWithMergedAction(newAction, /* canStart= */ notMetRequirements == 0);
|
||||
download = download.copyWithMergedAction(newAction, downloadManager.canStartDownloads());
|
||||
initialize();
|
||||
}
|
||||
|
||||
|
|
@ -866,7 +859,7 @@ public final class DownloadManager {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getId() + ' ' + Download.getStateString(state);
|
||||
return download.action.id + ' ' + Download.getStateString(state);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
|
|
@ -877,11 +870,6 @@ public final class DownloadManager {
|
|||
}
|
||||
}
|
||||
|
||||
public void setNotMetRequirements(@Requirements.RequirementFlags int notMetRequirements) {
|
||||
this.notMetRequirements = notMetRequirements;
|
||||
updateStopState();
|
||||
}
|
||||
|
||||
public void setManualStopReason(int manualStopReason) {
|
||||
this.manualStopReason = manualStopReason;
|
||||
updateStopState();
|
||||
|
|
@ -913,8 +901,8 @@ public final class DownloadManager {
|
|||
}
|
||||
|
||||
private void initialize(int initialState) {
|
||||
// Don't notify listeners with initial state until we make sure we don't switch to
|
||||
// another state immediately.
|
||||
// Don't notify listeners with initial state until we make sure we don't switch to another
|
||||
// state immediately.
|
||||
state = initialState;
|
||||
if (isInRemoveState()) {
|
||||
downloadManager.startDownloadThread(this);
|
||||
|
|
@ -929,7 +917,7 @@ public final class DownloadManager {
|
|||
}
|
||||
|
||||
private boolean canStart() {
|
||||
return manualStopReason == MANUAL_STOP_REASON_NONE && notMetRequirements == 0;
|
||||
return downloadManager.canStartDownloads() && manualStopReason == MANUAL_STOP_REASON_NONE;
|
||||
}
|
||||
|
||||
private void startOrQueue() {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2.offline;
|
||||
|
||||
import static com.google.android.exoplayer2.offline.Download.MANUAL_STOP_REASON_NONE;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
|
|
@ -55,17 +57,18 @@ public abstract class DownloadService extends Service {
|
|||
* <ul>
|
||||
* <li>{@link #KEY_DOWNLOAD_ACTION} - A {@link DownloadAction} defining the download to be
|
||||
* added.
|
||||
* <li>{@link #KEY_MANUAL_STOP_REASON} - An initial manual stop reason for the download. If
|
||||
* omitted {@link Download#MANUAL_STOP_REASON_NONE} is used.
|
||||
* <li>{@link #KEY_FOREGROUND} - See {@link #KEY_FOREGROUND}.
|
||||
* </ul>
|
||||
*/
|
||||
public static final String ACTION_ADD = "com.google.android.exoplayer.downloadService.action.ADD";
|
||||
|
||||
/**
|
||||
* Starts one or all of the current downloads. Extras:
|
||||
* Starts all downloads except those that are manually stopped (i.e. have a non-zero {@link
|
||||
* Download#manualStopReason}). Extras:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #KEY_CONTENT_ID} - The content id of a single download to start. If omitted, all
|
||||
* of the current downloads will be started.
|
||||
* <li>{@link #KEY_FOREGROUND} - See {@link #KEY_FOREGROUND}.
|
||||
* </ul>
|
||||
*/
|
||||
|
|
@ -73,20 +76,31 @@ public abstract class DownloadService extends Service {
|
|||
"com.google.android.exoplayer.downloadService.action.START";
|
||||
|
||||
/**
|
||||
* Stops one or all of the current downloads. Extras:
|
||||
* Stops all downloads. Extras:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #KEY_CONTENT_ID} - The content id of a single download to stop. If omitted, all of
|
||||
* the current downloads will be stopped.
|
||||
* <li>{@link #KEY_STOP_REASON} - An application provided reason for stopping the download or
|
||||
* downloads. Must not be {@link Download#MANUAL_STOP_REASON_NONE}. If omitted, the stop
|
||||
* reason will be {@link Download#MANUAL_STOP_REASON_UNDEFINED}.
|
||||
* <li>{@link #KEY_FOREGROUND} - See {@link #KEY_FOREGROUND}.
|
||||
* </ul>
|
||||
*/
|
||||
public static final String ACTION_STOP =
|
||||
"com.google.android.exoplayer.downloadService.action.STOP";
|
||||
|
||||
/**
|
||||
* Sets the manual stop reason for one or all downloads. To clear the manual stop reason, pass
|
||||
* {@link Download#MANUAL_STOP_REASON_NONE}. Extras:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #KEY_CONTENT_ID} - The content id of a single download to update with the manual
|
||||
* stop reason. If omitted, all downloads will be updated.
|
||||
* <li>{@link #KEY_MANUAL_STOP_REASON} - An application provided reason for stopping the
|
||||
* download or downloads, or {@link Download#MANUAL_STOP_REASON_NONE} to clear the manual
|
||||
* stop reason.
|
||||
* <li>{@link #KEY_FOREGROUND} - See {@link #KEY_FOREGROUND}.
|
||||
* </ul>
|
||||
*/
|
||||
public static final String ACTION_SET_MANUAL_STOP_REASON =
|
||||
"com.google.android.exoplayer.downloadService.action.SET_MANUAL_STOP_REASON";
|
||||
|
||||
/**
|
||||
* Removes an existing download. Extras:
|
||||
*
|
||||
|
|
@ -110,8 +124,11 @@ public abstract class DownloadService extends Service {
|
|||
*/
|
||||
public static final String KEY_CONTENT_ID = "content_id";
|
||||
|
||||
/** Key for the stop reason in {@link #ACTION_STOP} intents. */
|
||||
public static final String KEY_STOP_REASON = "stop_reason";
|
||||
/**
|
||||
* Key for the manual stop reason in {@link #ACTION_SET_MANUAL_STOP_REASON} and {@link
|
||||
* #ACTION_ADD} intents.
|
||||
*/
|
||||
public static final String KEY_MANUAL_STOP_REASON = "manual_stop_reason";
|
||||
|
||||
/**
|
||||
* Key for a boolean extra that can be set on any intent to indicate whether the service was
|
||||
|
|
@ -228,43 +245,31 @@ public abstract class DownloadService extends Service {
|
|||
Class<? extends DownloadService> clazz,
|
||||
DownloadAction downloadAction,
|
||||
boolean foreground) {
|
||||
return getIntent(context, clazz, ACTION_ADD)
|
||||
.putExtra(KEY_DOWNLOAD_ACTION, downloadAction)
|
||||
.putExtra(KEY_FOREGROUND, foreground);
|
||||
return buildAddActionIntent(
|
||||
context, clazz, downloadAction, MANUAL_STOP_REASON_NONE, foreground);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an {@link Intent} for stopping the download with the {@code id}. If {@code id} is null,
|
||||
* stops all downloads.
|
||||
* Builds an {@link Intent} for adding an action to be executed by the service.
|
||||
*
|
||||
* @param context A {@link Context}.
|
||||
* @param clazz The concrete download service being targeted by the intent.
|
||||
* @param id The content id, or null if all downloads should be stopped.
|
||||
* @param manualStopReason An application defined stop reason.
|
||||
* @param downloadAction The action to be executed.
|
||||
* @param manualStopReason An initial manual stop reason for the download, or {@link
|
||||
* Download#MANUAL_STOP_REASON_NONE} if the download should be started.
|
||||
* @param foreground Whether this intent will be used to start the service in the foreground.
|
||||
* @return Created Intent.
|
||||
*/
|
||||
public static Intent buildStopDownloadIntent(
|
||||
public static Intent buildAddActionIntent(
|
||||
Context context,
|
||||
Class<? extends DownloadService> clazz,
|
||||
@Nullable String id,
|
||||
int manualStopReason) {
|
||||
return getIntent(context, clazz, ACTION_STOP)
|
||||
.putExtra(KEY_CONTENT_ID, id)
|
||||
.putExtra(KEY_STOP_REASON, manualStopReason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an {@link Intent} for starting the download with the {@code id}. If {@code id} is null,
|
||||
* starts all downloads.
|
||||
*
|
||||
* @param context A {@link Context}.
|
||||
* @param clazz The concrete download service being targeted by the intent.
|
||||
* @param id The content id, or null if all downloads should be started.
|
||||
* @return Created Intent.
|
||||
*/
|
||||
public static Intent buildStartDownloadIntent(
|
||||
Context context, Class<? extends DownloadService> clazz, @Nullable String id) {
|
||||
return getIntent(context, clazz, ACTION_START).putExtra(KEY_CONTENT_ID, id);
|
||||
DownloadAction downloadAction,
|
||||
int manualStopReason,
|
||||
boolean foreground) {
|
||||
return getIntent(context, clazz, ACTION_ADD)
|
||||
.putExtra(KEY_DOWNLOAD_ACTION, downloadAction)
|
||||
.putExtra(KEY_MANUAL_STOP_REASON, manualStopReason)
|
||||
.putExtra(KEY_FOREGROUND, foreground);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -283,6 +288,26 @@ public abstract class DownloadService extends Service {
|
|||
.putExtra(KEY_FOREGROUND, foreground);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an {@link Intent} for setting the manual stop reason for one or all downloads. To clear
|
||||
* the manual stop reason, pass {@link Download#MANUAL_STOP_REASON_NONE}.
|
||||
*
|
||||
* @param context A {@link Context}.
|
||||
* @param clazz The concrete download service being targeted by the intent.
|
||||
* @param id The content id, or {@code null} to set the manual stop reason for all downloads.
|
||||
* @param manualStopReason An application defined stop reason.
|
||||
* @return Created Intent.
|
||||
*/
|
||||
public static Intent buildSetManualStopReasonIntent(
|
||||
Context context,
|
||||
Class<? extends DownloadService> clazz,
|
||||
@Nullable String id,
|
||||
int manualStopReason) {
|
||||
return getIntent(context, clazz, ACTION_STOP)
|
||||
.putExtra(KEY_CONTENT_ID, id)
|
||||
.putExtra(KEY_MANUAL_STOP_REASON, manualStopReason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the service, adding an action to be executed.
|
||||
*
|
||||
|
|
@ -358,9 +383,11 @@ public abstract class DownloadService extends Service {
|
|||
Class<? extends DownloadService> clazz = getClass();
|
||||
DownloadManagerHelper downloadManagerHelper = downloadManagerListeners.get(clazz);
|
||||
if (downloadManagerHelper == null) {
|
||||
DownloadManager downloadManager = getDownloadManager();
|
||||
downloadManager.startDownloads();
|
||||
downloadManagerHelper =
|
||||
new DownloadManagerHelper(
|
||||
getApplicationContext(), getDownloadManager(), getScheduler(), clazz);
|
||||
getApplicationContext(), downloadManager, getScheduler(), clazz);
|
||||
downloadManagerListeners.put(clazz, downloadManagerHelper);
|
||||
}
|
||||
downloadManager = downloadManagerHelper.downloadManager;
|
||||
|
|
@ -390,32 +417,33 @@ public abstract class DownloadService extends Service {
|
|||
case ACTION_ADD:
|
||||
DownloadAction downloadAction = intent.getParcelableExtra(KEY_DOWNLOAD_ACTION);
|
||||
if (downloadAction == null) {
|
||||
Log.e(TAG, "Ignored ADD action: Missing download_action extra");
|
||||
Log.e(TAG, "Ignored ADD: Missing download_action extra");
|
||||
} else {
|
||||
downloadManager.addDownload(downloadAction);
|
||||
int manualStopReason =
|
||||
intent.getIntExtra(KEY_MANUAL_STOP_REASON, Download.MANUAL_STOP_REASON_NONE);
|
||||
downloadManager.addDownload(downloadAction, manualStopReason);
|
||||
}
|
||||
break;
|
||||
case ACTION_START:
|
||||
String contentId = intent.getStringExtra(KEY_CONTENT_ID);
|
||||
if (contentId == null) {
|
||||
downloadManager.startDownloads();
|
||||
} else {
|
||||
downloadManager.startDownload(contentId);
|
||||
}
|
||||
downloadManager.startDownloads();
|
||||
break;
|
||||
case ACTION_STOP:
|
||||
contentId = intent.getStringExtra(KEY_CONTENT_ID);
|
||||
int stopReason = intent.getIntExtra(KEY_STOP_REASON, Download.MANUAL_STOP_REASON_UNDEFINED);
|
||||
if (contentId == null) {
|
||||
downloadManager.stopDownloads(stopReason);
|
||||
downloadManager.stopDownloads();
|
||||
break;
|
||||
case ACTION_SET_MANUAL_STOP_REASON:
|
||||
if (!intent.hasExtra(KEY_MANUAL_STOP_REASON)) {
|
||||
Log.e(TAG, "Ignored SET_MANUAL_STOP_REASON: Missing manual_stop_reason extra");
|
||||
} else {
|
||||
downloadManager.stopDownload(contentId, stopReason);
|
||||
String contentId = intent.getStringExtra(KEY_CONTENT_ID);
|
||||
int manualStopReason =
|
||||
intent.getIntExtra(KEY_MANUAL_STOP_REASON, Download.MANUAL_STOP_REASON_NONE);
|
||||
downloadManager.setManualStopReason(contentId, manualStopReason);
|
||||
}
|
||||
break;
|
||||
case ACTION_REMOVE:
|
||||
contentId = intent.getStringExtra(KEY_CONTENT_ID);
|
||||
String contentId = intent.getStringExtra(KEY_CONTENT_ID);
|
||||
if (contentId == null) {
|
||||
Log.e(TAG, "Ignored REMOVE action: Missing content_id extra");
|
||||
Log.e(TAG, "Ignored REMOVE: Missing content_id extra");
|
||||
} else {
|
||||
downloadManager.removeDownload(contentId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,14 +47,16 @@ import org.robolectric.shadows.ShadowLog;
|
|||
@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class})
|
||||
public class DownloadManagerTest {
|
||||
|
||||
/* Used to check if condition becomes true in this time interval. */
|
||||
/** Used to check if condition becomes true in this time interval. */
|
||||
private static final int ASSERT_TRUE_TIMEOUT = 10000;
|
||||
/* Used to check if condition stays false for this time interval. */
|
||||
/** Used to check if condition stays false for this time interval. */
|
||||
private static final int ASSERT_FALSE_TIME = 1000;
|
||||
/* Maximum retry delay in DownloadManager. */
|
||||
/** Maximum retry delay in DownloadManager. */
|
||||
private static final int MAX_RETRY_DELAY = 5000;
|
||||
/* Maximum number of times a downloader can be restarted before doing a released check. */
|
||||
/** Maximum number of times a downloader can be restarted before doing a released check. */
|
||||
private static final int MAX_STARTS_BEFORE_RELEASED = 1;
|
||||
/** A manual stop reason. */
|
||||
private static final int APP_STOP_REASON = 1;
|
||||
/** The minimum number of times a task must be retried before failing. */
|
||||
private static final int MIN_RETRY_COUNT = 3;
|
||||
|
||||
|
|
@ -388,17 +390,18 @@ public class DownloadManagerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void stopAndResumeSingleDownload() throws Throwable {
|
||||
public void manuallyStopAndResumeSingleDownload() throws Throwable {
|
||||
DownloadRunner runner = new DownloadRunner(uri1).postDownloadAction();
|
||||
TaskWrapper task = runner.getTask();
|
||||
|
||||
task.assertDownloading();
|
||||
|
||||
runOnMainThread(() -> downloadManager.stopDownload(task.taskId));
|
||||
runOnMainThread(() -> downloadManager.setManualStopReason(task.taskId, APP_STOP_REASON));
|
||||
|
||||
task.assertStopped();
|
||||
|
||||
runOnMainThread(() -> downloadManager.startDownload(task.taskId));
|
||||
runOnMainThread(
|
||||
() -> downloadManager.setManualStopReason(task.taskId, Download.MANUAL_STOP_REASON_NONE));
|
||||
|
||||
runner.getDownloader(1).assertStarted().unblock();
|
||||
|
||||
|
|
@ -406,13 +409,13 @@ public class DownloadManagerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void stoppedDownloadCanBeCancelled() throws Throwable {
|
||||
public void manuallyStoppedDownloadCanBeCancelled() throws Throwable {
|
||||
DownloadRunner runner = new DownloadRunner(uri1).postDownloadAction();
|
||||
TaskWrapper task = runner.getTask();
|
||||
|
||||
task.assertDownloading();
|
||||
|
||||
runOnMainThread(() -> downloadManager.stopDownload(task.taskId));
|
||||
runOnMainThread(() -> downloadManager.setManualStopReason(task.taskId, APP_STOP_REASON));
|
||||
|
||||
task.assertStopped();
|
||||
|
||||
|
|
@ -424,7 +427,7 @@ public class DownloadManagerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void stoppedSingleDownload_doesNotAffectOthers() throws Throwable {
|
||||
public void manuallyStoppedSingleDownload_doesNotAffectOthers() throws Throwable {
|
||||
DownloadRunner runner1 = new DownloadRunner(uri1);
|
||||
DownloadRunner runner2 = new DownloadRunner(uri2);
|
||||
DownloadRunner runner3 = new DownloadRunner(uri3);
|
||||
|
|
@ -432,7 +435,8 @@ public class DownloadManagerTest {
|
|||
runner1.postDownloadAction().getTask().assertDownloading();
|
||||
runner2.postDownloadAction().postRemoveAction().getTask().assertRemoving();
|
||||
|
||||
runOnMainThread(() -> downloadManager.stopDownload(runner1.getTask().taskId));
|
||||
runOnMainThread(
|
||||
() -> downloadManager.setManualStopReason(runner1.getTask().taskId, APP_STOP_REASON));
|
||||
|
||||
runner1.getTask().assertStopped();
|
||||
|
||||
|
|
@ -460,9 +464,9 @@ public class DownloadManagerTest {
|
|||
maxActiveDownloadTasks,
|
||||
MIN_RETRY_COUNT,
|
||||
new Requirements(0));
|
||||
downloadManager.startDownloads();
|
||||
downloadManagerListener =
|
||||
new TestDownloadManagerListener(downloadManager, dummyMainThread);
|
||||
downloadManager.startDownloads();
|
||||
});
|
||||
downloadManagerListener.waitUntilInitialized();
|
||||
} catch (Throwable throwable) {
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ public class DownloadTest {
|
|||
DownloadBuilder downloadBuilder =
|
||||
new DownloadBuilder(downloadAction)
|
||||
.setState(Download.STATE_STOPPED)
|
||||
.setManualStopReason(Download.MANUAL_STOP_REASON_UNDEFINED);
|
||||
.setManualStopReason(/* manualStopReason= */ 1);
|
||||
Download download = downloadBuilder.build();
|
||||
|
||||
Download mergedDownload = download.copyWithMergedAction(downloadAction, /* canStart= */ true);
|
||||
|
|
@ -170,7 +170,7 @@ public class DownloadTest {
|
|||
DownloadBuilder downloadBuilder =
|
||||
new DownloadBuilder(downloadAction)
|
||||
.setState(Download.STATE_COMPLETED)
|
||||
.setManualStopReason(Download.MANUAL_STOP_REASON_UNDEFINED);
|
||||
.setManualStopReason(/* manualStopReason= */ 1);
|
||||
Download download = downloadBuilder.build();
|
||||
|
||||
Download mergedDownload = download.copyWithMergedAction(downloadAction, /* canStart= */ true);
|
||||
|
|
|
|||
Loading…
Reference in a new issue