Commit c9b848e5 by eguven Committed by Oliver Woodman

Synchronously change to next state from downloading state

PiperOrigin-RevId: 231586206
parent 55b58148
...@@ -310,9 +310,10 @@ public final class DownloadManager { ...@@ -310,9 +310,10 @@ public final class DownloadManager {
/** Returns whether there are no active downloads. */ /** Returns whether there are no active downloads. */
public boolean isIdle() { public boolean isIdle() {
Assertions.checkState(!released); Assertions.checkState(!released);
if (!initialized) { if (!initialized || !activeDownloads.isEmpty()) {
return false; return false;
} }
// Still need to check all downloads as there might be remove tasks going on.
for (int i = 0; i < downloads.size(); i++) { for (int i = 0; i < downloads.size(); i++) {
if (!downloads.get(i).isIdle()) { if (!downloads.get(i).isIdle()) {
return false; return false;
...@@ -365,6 +366,14 @@ public final class DownloadManager { ...@@ -365,6 +366,14 @@ public final class DownloadManager {
} }
} }
private void maybeRestartDownload(Download download) {
if (activeDownloads.contains(download)) {
download.start();
} else {
maybeStartDownload(download);
}
}
private void maybeNotifyListenersIdle() { private void maybeNotifyListenersIdle() {
if (!isIdle()) { if (!isIdle()) {
return; return;
...@@ -540,7 +549,7 @@ public final class DownloadManager { ...@@ -540,7 +549,7 @@ public final class DownloadManager {
this.startTimeMs = System.currentTimeMillis(); this.startTimeMs = System.currentTimeMillis();
actionQueue = new ArrayDeque<>(); actionQueue = new ArrayDeque<>();
actionQueue.add(action); actionQueue.add(action);
initialize(/* restart= */ false); initialize();
} }
public boolean addAction(DownloadAction newAction) { public boolean addAction(DownloadAction newAction) {
...@@ -562,12 +571,12 @@ public final class DownloadManager { ...@@ -562,12 +571,12 @@ public final class DownloadManager {
setState(STATE_REMOVING); setState(STATE_REMOVING);
} }
} else if (!action.equals(updatedAction)) { } else if (!action.equals(updatedAction)) {
Assertions.checkState(
state == STATE_DOWNLOADING || state == STATE_QUEUED || state == STATE_STOPPED);
if (state == STATE_DOWNLOADING) { if (state == STATE_DOWNLOADING) {
stopDownloadThread(); stopDownloadThread();
} else {
Assertions.checkState(state == STATE_QUEUED || state == STATE_STOPPED);
initialize(/* restart= */ false);
} }
initialize();
} }
return true; return true;
} }
...@@ -633,13 +642,14 @@ public final class DownloadManager { ...@@ -633,13 +642,14 @@ public final class DownloadManager {
public void updateStopFlags(int flags, int values) { public void updateStopFlags(int flags, int values) {
stopFlags = (values & flags) | (stopFlags & ~flags); stopFlags = (values & flags) | (stopFlags & ~flags);
if (stopFlags != 0) { if (stopFlags != 0) {
if (state == STATE_DOWNLOADING) { if (state == STATE_DOWNLOADING || state == STATE_QUEUED) {
stopDownloadThread(); if (state == STATE_DOWNLOADING) {
} else if (state == STATE_QUEUED) { stopDownloadThread();
}
setState(STATE_STOPPED); setState(STATE_STOPPED);
} }
} else if (state == STATE_STOPPED) { } else if (state == STATE_STOPPED) {
startOrQueue(/* restart= */ false); startOrQueue();
} }
} }
...@@ -650,7 +660,7 @@ public final class DownloadManager { ...@@ -650,7 +660,7 @@ public final class DownloadManager {
notMetRequirements != 0 ? STOP_FLAG_REQUIREMENTS_NOT_MET : 0); notMetRequirements != 0 ? STOP_FLAG_REQUIREMENTS_NOT_MET : 0);
} }
private void initialize(boolean restart) { private void initialize() {
DownloadAction action = actionQueue.peek(); DownloadAction action = actionQueue.peek();
if (action.isRemoveAction) { if (action.isRemoveAction) {
if (!downloadManager.released) { if (!downloadManager.released) {
...@@ -660,18 +670,14 @@ public final class DownloadManager { ...@@ -660,18 +670,14 @@ public final class DownloadManager {
} else if (stopFlags != 0) { } else if (stopFlags != 0) {
setState(STATE_STOPPED); setState(STATE_STOPPED);
} else { } else {
startOrQueue(restart); startOrQueue();
} }
} }
private void startOrQueue(boolean restart) { private void startOrQueue() {
// Set to queued state but don't notify listeners until we make sure we can't start now. // Set to queued state but don't notify listeners until we make sure we can't start now.
state = STATE_QUEUED; state = STATE_QUEUED;
if (restart) { downloadManager.maybeRestartDownload(this);
start();
} else {
downloadManager.maybeStartDownload(this);
}
if (state == STATE_QUEUED) { if (state == STATE_QUEUED) {
downloadManager.onDownloadStateChange(this); downloadManager.onDownloadStateChange(this);
} }
...@@ -683,6 +689,9 @@ public final class DownloadManager { ...@@ -683,6 +689,9 @@ public final class DownloadManager {
} }
private void startDownloadThread(DownloadAction action) { private void startDownloadThread(DownloadAction action) {
if (downloadThread != null) {
return;
}
downloader = downloaderFactory.createDownloader(action); downloader = downloaderFactory.createDownloader(action);
downloadThread = downloadThread =
new DownloadThread( new DownloadThread(
...@@ -690,29 +699,37 @@ public final class DownloadManager { ...@@ -690,29 +699,37 @@ public final class DownloadManager {
} }
private void stopDownloadThread() { private void stopDownloadThread() {
Assertions.checkNotNull(downloadThread).cancel(); if (!downloadThread.isRemoveThread) {
Assertions.checkNotNull(downloadThread).cancel();
}
} }
private void onDownloadThreadStopped(@Nullable Throwable finalError) { private void onDownloadThreadStopped(@Nullable Throwable error) {
failureReason = FAILURE_REASON_NONE; failureReason = FAILURE_REASON_NONE;
if (!downloadThread.isCanceled) { boolean isCanceled = downloadThread.isCanceled;
if (finalError != null && state != STATE_REMOVING && state != STATE_RESTARTING) { downloadThread = null;
failureReason = FAILURE_REASON_UNKNOWN; if (isCanceled) {
setState(STATE_FAILED); if (!isIdle()) {
return; startDownloadThread(actionQueue.peek());
} }
if (actionQueue.size() == 1) { return;
if (state == STATE_REMOVING) { }
setState(STATE_REMOVED); if (error != null && state == STATE_DOWNLOADING) {
} else { failureReason = FAILURE_REASON_UNKNOWN;
Assertions.checkState(state == STATE_DOWNLOADING); setState(STATE_FAILED);
setState(STATE_COMPLETED); return;
} }
return; if (actionQueue.size() == 1) {
if (state == STATE_REMOVING) {
setState(STATE_REMOVED);
} else {
Assertions.checkState(state == STATE_DOWNLOADING);
setState(STATE_COMPLETED);
} }
actionQueue.remove(); return;
} }
initialize(/* restart= */ state == STATE_DOWNLOADING); actionQueue.remove();
initialize();
} }
} }
...@@ -720,7 +737,7 @@ public final class DownloadManager { ...@@ -720,7 +737,7 @@ public final class DownloadManager {
private final Download download; private final Download download;
private final Downloader downloader; private final Downloader downloader;
private final boolean remove; private final boolean isRemoveThread;
private final int minRetryCount; private final int minRetryCount;
private final Handler callbackHandler; private final Handler callbackHandler;
private final Thread thread; private final Thread thread;
...@@ -729,12 +746,12 @@ public final class DownloadManager { ...@@ -729,12 +746,12 @@ public final class DownloadManager {
private DownloadThread( private DownloadThread(
Download download, Download download,
Downloader downloader, Downloader downloader,
boolean remove, boolean isRemoveThread,
int minRetryCount, int minRetryCount,
Handler callbackHandler) { Handler callbackHandler) {
this.download = download; this.download = download;
this.downloader = downloader; this.downloader = downloader;
this.remove = remove; this.isRemoveThread = isRemoveThread;
this.minRetryCount = minRetryCount; this.minRetryCount = minRetryCount;
this.callbackHandler = callbackHandler; this.callbackHandler = callbackHandler;
thread = new Thread(this); thread = new Thread(this);
...@@ -754,7 +771,7 @@ public final class DownloadManager { ...@@ -754,7 +771,7 @@ public final class DownloadManager {
logd("Download is started", download); logd("Download is started", download);
Throwable error = null; Throwable error = null;
try { try {
if (remove) { if (isRemoveThread) {
downloader.remove(); downloader.remove();
} else { } else {
int errorCount = 0; int errorCount = 0;
......
...@@ -182,13 +182,11 @@ public final class DownloadState { ...@@ -182,13 +182,11 @@ public final class DownloadState {
byte[] customMetadata) { byte[] customMetadata) {
Assertions.checkState( Assertions.checkState(
failureReason == FAILURE_REASON_NONE ? state != STATE_FAILED : state == STATE_FAILED); failureReason == FAILURE_REASON_NONE ? state != STATE_FAILED : state == STATE_FAILED);
Assertions.checkState(stopFlags == 0 || (state != STATE_DOWNLOADING && state != STATE_QUEUED));
Assertions.checkState( Assertions.checkState(
(stopFlags & STOP_FLAG_REQUIREMENTS_NOT_MET) == 0 (stopFlags & STOP_FLAG_REQUIREMENTS_NOT_MET) == 0
? notMetRequirements == 0 ? notMetRequirements == 0
: notMetRequirements != 0); : notMetRequirements != 0);
// TODO enable this when we start changing state immediately
// Assertions.checkState(stopFlags == 0 || (state != STATE_DOWNLOADING && state !=
// STATE_QUEUED));
this.id = id; this.id = id;
this.type = type; this.type = type;
this.uri = uri; this.uri = uri;
......
...@@ -53,6 +53,7 @@ import org.mockito.MockitoAnnotations; ...@@ -53,6 +53,7 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLog;
/** Tests {@link DownloadManager}. */ /** Tests {@link DownloadManager}. */
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
...@@ -73,6 +74,7 @@ public class DownloadManagerDashTest { ...@@ -73,6 +74,7 @@ public class DownloadManagerDashTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
ShadowLog.stream = System.out;
dummyMainThread = new DummyMainThread(); dummyMainThread = new DummyMainThread();
Context context = RuntimeEnvironment.application; Context context = RuntimeEnvironment.application;
tempFolder = Util.createTempDirectory(context, "ExoPlayerTest"); tempFolder = Util.createTempDirectory(context, "ExoPlayerTest");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment