Support stopping/starting single downloads

Also added intent actions to stop/start one or all downloads.

Issue: #4433
Issue: #4860
PiperOrigin-RevId: 234481515
This commit is contained in:
eguven 2019-02-18 15:55:27 +00:00 committed by Andrew Lewis
parent 2b67f2a626
commit 03e28d4689
3 changed files with 176 additions and 8 deletions

View file

@ -260,7 +260,7 @@ public final class DownloadManager {
/** Signals all downloads to stop. Call {@link #startDownloads()} to let them to be started. */
public void stopDownloads() {
stopDownloads(0);
stopDownloads(/* manualStopReason= */ 0);
}
/**
@ -277,6 +277,45 @@ public final class DownloadManager {
}
}
/**
* Clears {@link DownloadState#STOP_FLAG_MANUAL} flag 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) {
Download download = getDownload(id);
if (download != null) {
logd("download is started manually", download);
download.clearManualStopReason();
}
}
/**
* 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, /* manualStopReason= */ 0);
}
/**
* 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.
*/
public void stopDownload(String id, int manualStopReason) {
Download download = getDownload(id);
if (download != null) {
logd("download is stopped manually", download);
download.setManualStopReason(manualStopReason);
}
}
/**
* Handles the given action.
*
@ -307,13 +346,8 @@ public final class DownloadManager {
@Nullable
public DownloadState getDownloadState(String id) {
Assertions.checkState(!released);
for (int i = 0; i < downloads.size(); i++) {
Download download = downloads.get(i);
if (download.getId().equals(id)) {
return download.getDownloadState();
}
}
return null;
Download download = getDownload(id);
return download != null ? download.getDownloadState() : null;
}
/** Returns the states of all current downloads. */
@ -418,6 +452,17 @@ public final class DownloadManager {
}
}
@Nullable
private Download getDownload(String id) {
for (int i = 0; i < downloads.size(); i++) {
Download download = downloads.get(i);
if (download.getId().equals(id)) {
return download;
}
}
return null;
}
private void loadActions() {
fileIOHandler.post(
() -> {

View file

@ -43,6 +43,14 @@ public abstract class DownloadService extends Service {
/** Starts a download service, adding a new {@link DownloadAction} to be executed. */
public static final String ACTION_ADD = "com.google.android.exoplayer.downloadService.action.ADD";
/** Stops one or all downloads. */
public static final String ACTION_STOP =
"com.google.android.exoplayer.downloadService.action.STOP";
/** Starts one or all downloads. */
public static final String ACTION_START =
"com.google.android.exoplayer.downloadService.action.START";
/** Like {@link #ACTION_INIT}, but with {@link #KEY_FOREGROUND} implicitly set to true. */
private static final String ACTION_RESTART =
"com.google.android.exoplayer.downloadService.action.RESTART";
@ -50,6 +58,12 @@ public abstract class DownloadService extends Service {
/** Key for the {@link DownloadAction} in an {@link #ACTION_ADD} intent. */
public static final String KEY_DOWNLOAD_ACTION = "download_action";
/** Key for content id in an {@link #ACTION_STOP} or {@link #ACTION_START} intent. */
public static final String KEY_CONTENT_ID = "content_id";
/** Key for manual stop reason in an {@link #ACTION_STOP} intent. */
public static final String KEY_STOP_REASON = "stop_reason";
/** Invalid foreground notification id which can be used to run the service in the background. */
public static final int FOREGROUND_NOTIFICATION_ID_NONE = 0;
@ -165,6 +179,40 @@ public abstract class DownloadService extends Service {
.putExtra(KEY_FOREGROUND, foreground);
}
/**
* Builds an {@link Intent} for stopping the download with the {@code id}. If {@code id} is null,
* stops 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 stopped.
* @param manualStopReason An application defined stop reason.
* @return Created Intent.
*/
public static Intent buildStopDownloadIntent(
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);
}
/**
* Starts the service, adding an action to be executed.
*
@ -263,6 +311,23 @@ public abstract class DownloadService extends Service {
}
}
break;
case ACTION_STOP:
String stopDownloadId = intent.getStringExtra(KEY_CONTENT_ID);
int stopReason = intent.getIntExtra(KEY_STOP_REASON, 0);
if (stopDownloadId == null) {
downloadManager.stopDownloads(stopReason);
} else {
downloadManager.stopDownload(stopDownloadId, stopReason);
}
break;
case ACTION_START:
String startDownloadId = intent.getStringExtra(KEY_CONTENT_ID);
if (startDownloadId == null) {
downloadManager.startDownloads();
} else {
downloadManager.startDownload(startDownloadId);
}
break;
default:
Log.e(TAG, "Ignoring unrecognized action: " + intentAction);
break;

View file

@ -403,6 +403,64 @@ public class DownloadManagerTest {
downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
}
@Test
public void stopAndResumeSingleDownload() throws Throwable {
DownloadRunner runner = new DownloadRunner(uri1).postDownloadAction();
TaskWrapper task = runner.getTask();
task.assertDownloading();
runOnMainThread(() -> downloadManager.stopDownload(task.taskId));
task.assertStopped();
runOnMainThread(() -> downloadManager.startDownload(task.taskId));
runner.getDownloader(1).assertStarted().unblock();
downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
}
@Test
public void stoppedDownloadCanBeCancelled() throws Throwable {
DownloadRunner runner = new DownloadRunner(uri1).postDownloadAction();
TaskWrapper task = runner.getTask();
task.assertDownloading();
runOnMainThread(() -> downloadManager.stopDownload(task.taskId));
task.assertStopped();
runner.postRemoveAction();
runner.getDownloader(1).assertStarted().unblock();
task.assertRemoved();
downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
}
@Test
public void stoppedSingleDownload_doesNotAffectOthers() throws Throwable {
DownloadRunner runner1 = new DownloadRunner(uri1);
DownloadRunner runner2 = new DownloadRunner(uri2);
DownloadRunner runner3 = new DownloadRunner(uri3);
runner1.postDownloadAction().getTask().assertDownloading();
runner2.postRemoveAction().getTask().assertRemoving();
runOnMainThread(() -> downloadManager.stopDownload(runner1.getTask().taskId));
runner1.getTask().assertStopped();
// Other downloads aren't affected.
runner2.getDownloader(0).unblock().assertReleased();
// New download actions can be added and they start.
runner3.postDownloadAction().getDownloader(0).assertStarted().unblock();
downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
}
private void setUpDownloadManager(final int maxActiveDownloadTasks) throws Exception {
if (downloadManager != null) {
releaseDownloadManager();