From a940d8bc9d70ea59952ebfe3c60c502a7206825e Mon Sep 17 00:00:00 2001 From: eguven Date: Thu, 3 Jan 2019 14:54:49 +0000 Subject: [PATCH] Use removing and restarting state internally in DownloadManager PiperOrigin-RevId: 227682159 --- .../exoplayer2/offline/DownloadManager.java | 184 ++++++++++-------- 1 file changed, 100 insertions(+), 84 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadManager.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadManager.java index 94013bb73f..035d3a90b0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadManager.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadManager.java @@ -175,7 +175,6 @@ public final class DownloadManager { for (int i = 0; i < downloads.size(); i++) { downloads.get(i).clearStopFlags(STOP_FLAG_STOPPED); } - maybeStartDownloads(); logd("Downloads are started"); } } @@ -254,7 +253,7 @@ public final class DownloadManager { return false; } for (int i = 0; i < downloads.size(); i++) { - if (downloads.get(i).isStarted()) { + if (!downloads.get(i).isIdle()) { return false; } } @@ -284,8 +283,7 @@ public final class DownloadManager { private void addDownloadForAction(DownloadAction action) { for (int i = 0; i < downloads.size(); i++) { Download download = downloads.get(i); - if (download.action.isSameMedia(action)) { - download.addAction(action); + if (download.addAction(action)) { logd("Action is added to existing download", download); return; } @@ -296,33 +294,27 @@ public final class DownloadManager { logd("Download is added", download); } - /** - * Iterates through the download queue and starts any download if all of the following are true: - * - * - */ private void maybeStartDownloads() { - if (!initialized || released) { - return; - } for (int i = 0; i < downloads.size(); i++) { maybeStartDownload(downloads.get(i)); } } private void maybeStartDownload(Download download) { - if (download.action.isRemoveAction) { - download.start(); - } else if (activeDownloads.size() < maxActiveDownloads) { + if (initialized && !released && activeDownloads.size() < maxActiveDownloads) { if (download.start()) { activeDownloads.add(download); } } } + private void maybeRestartDownload(Download download) { + Assertions.checkState(activeDownloads.contains(download)); + if (initialized && !released) { + download.start(); + } + } + private void maybeNotifyListenersIdle() { if (!isIdle()) { return; @@ -337,8 +329,8 @@ public final class DownloadManager { if (released) { return; } - boolean stopped = !download.isStarted(); - if (stopped) { + boolean idle = download.isIdle(); + if (idle) { activeDownloads.remove(download); } notifyListenersDownloadStateChange(download); @@ -346,7 +338,7 @@ public final class DownloadManager { downloads.remove(download); saveActions(); } - if (stopped) { + if (idle) { maybeStartDownloads(); maybeNotifyListenersIdle(); } @@ -380,17 +372,18 @@ public final class DownloadManager { for (DownloadAction action : actions) { addDownloadForAction(action); } - logd("Downloads are created."); - initialized = true; - for (Listener listener : listeners) { - listener.onInitialized(DownloadManager.this); - } if (!actionQueue.isEmpty()) { while (!actionQueue.isEmpty()) { addDownloadForAction(actionQueue.remove()); } saveActions(); } + logd("Downloads are created."); + initialized = true; + for (Listener listener : listeners) { + listener.onInitialized(DownloadManager.this); + } + maybeStartDownloads(); }); }); } @@ -433,7 +426,6 @@ public final class DownloadManager { private final int minRetryCount; private final long startTimeMs; private final ArrayDeque actionQueue; - private DownloadAction action; /** The current state of the download. */ @DownloadState.State private int state; @@ -456,29 +448,36 @@ public final class DownloadManager { this.startTimeMs = System.currentTimeMillis(); actionQueue = new ArrayDeque<>(); actionQueue.add(action); - - // Don't notify listeners until we make sure the state doesn't change immediately. - state = STATE_QUEUED; - setActionAndUpdateState(action); - downloadManager.maybeStartDownload(this); - if (state == STATE_QUEUED) { - downloadManager.onDownloadStateChange(this); - } + initialize(/* restart= */ false); } - public void addAction(DownloadAction newAction) { + public boolean addAction(DownloadAction newAction) { + DownloadAction action = actionQueue.peek(); + if (!action.isSameMedia(newAction)) { + return false; + } Assertions.checkState(action.type.equals(newAction.type)); actionQueue.add(newAction); DownloadAction updatedAction = DownloadActionUtil.mergeActions(actionQueue); - if (action.equals(updatedAction)) { - return; - } - if (state == STATE_DOWNLOADING) { - stopDownloadThread(); - } else { - Assertions.checkState(state == STATE_QUEUED || state == STATE_STOPPED); - setActionAndUpdateState(updatedAction); + if (state == STATE_REMOVING) { + Assertions.checkState(updatedAction.isRemoveAction); + if (actionQueue.size() > 1) { + setState(STATE_RESTARTING); + } + } else if (state == STATE_RESTARTING) { + Assertions.checkState(updatedAction.isRemoveAction); + if (actionQueue.size() == 1) { + setState(STATE_REMOVING); + } + } else if (!action.equals(updatedAction)) { + if (state == STATE_DOWNLOADING) { + stopDownloadThread(); + } else { + Assertions.checkState(state == STATE_QUEUED || state == STATE_STOPPED); + initialize(/* restart= */ false); + } } + return true; } public DownloadState getDownloadState() { @@ -490,20 +489,13 @@ public final class DownloadManager { downloadedBytes = downloader.getDownloadedBytes(); totalBytes = downloader.getTotalBytes(); } - int newState = state; - if (action.isRemoveAction) { - if (state == STATE_DOWNLOADING) { - newState = actionQueue.size() > 1 ? STATE_RESTARTING : STATE_REMOVING; - } else if (state == STATE_COMPLETED || state == STATE_FAILED) { - newState = STATE_REMOVED; - } - } + DownloadAction action = actionQueue.peek(); return new DownloadState( action.id, action.type, action.uri, action.customCacheKey, - newState, + state, downloadPercentage, downloadedBytes, totalBytes, @@ -515,30 +507,24 @@ public final class DownloadManager { action.data); } - /** Returns whether the download is finished. */ public boolean isFinished() { - return state == STATE_FAILED || state == STATE_COMPLETED; + return state == STATE_FAILED || state == STATE_COMPLETED || state == STATE_REMOVED; } - /** Returns whether the download is started. */ - public boolean isStarted() { - return state == STATE_DOWNLOADING; + public boolean isIdle() { + return state != STATE_DOWNLOADING && state != STATE_REMOVING && state != STATE_RESTARTING; } @Override public String toString() { - String actionString = action.isRemoveAction ? "remove" : "download"; - return id + ' ' + actionString + ' ' + DownloadState.getStateString(state); + return id + ' ' + DownloadState.getStateString(state); } public boolean start() { if (state != STATE_QUEUED) { return false; } - downloader = downloaderFactory.createDownloader(action); - downloadThread = - new DownloadThread( - this, downloader, action.isRemoveAction, minRetryCount, downloadManager.handler); + startDownloadThread(actionQueue.peek()); setState(STATE_DOWNLOADING); return true; } @@ -560,28 +546,53 @@ public final class DownloadManager { private void updateStopFlags(int mask, int flags) { stopFlags = (flags & mask) | (stopFlags & ~mask); if (stopFlags != 0) { - if (!action.isRemoveAction) { - if (state == STATE_DOWNLOADING) { - stopDownloadThread(); - } else if (state == STATE_QUEUED) { - setState(STATE_STOPPED); - } + if (state == STATE_DOWNLOADING) { + stopDownloadThread(); + } else if (state == STATE_QUEUED) { + setState(STATE_STOPPED); } } else if (state == STATE_STOPPED) { - setState(STATE_QUEUED); + startOrQueue(/* restart= */ false); } } - private void setActionAndUpdateState(DownloadAction action) { - this.action = action; - setState(!this.action.isRemoveAction && stopFlags != 0 ? STATE_STOPPED : STATE_QUEUED); + private void initialize(boolean restart) { + DownloadAction action = actionQueue.peek(); + if (action.isRemoveAction) { + if (!downloadManager.released) { + startDownloadThread(action); + } + setState(actionQueue.size() == 1 ? STATE_REMOVING : STATE_RESTARTING); + } else if (stopFlags != 0) { + setState(STATE_STOPPED); + } else { + startOrQueue(restart); + } + } + + private void startOrQueue(boolean restart) { + // Set to queued state but don't notify listeners until we make sure we can't start now. + state = STATE_QUEUED; + if (restart) { + downloadManager.maybeRestartDownload(this); + } else { + downloadManager.maybeStartDownload(this); + } + if (state == STATE_QUEUED) { + downloadManager.onDownloadStateChange(this); + } } private void setState(@DownloadState.State int newState) { - if (state != newState) { - state = newState; - downloadManager.onDownloadStateChange(this); - } + state = newState; + downloadManager.onDownloadStateChange(this); + } + + private void startDownloadThread(DownloadAction action) { + downloader = downloaderFactory.createDownloader(action); + downloadThread = + new DownloadThread( + this, downloader, action.isRemoveAction, minRetryCount, downloadManager.handler); } private void stopDownloadThread() { @@ -591,18 +602,23 @@ public final class DownloadManager { private void onDownloadThreadStopped(@Nullable Throwable finalError) { failureReason = FAILURE_REASON_NONE; if (!downloadThread.isCanceled) { - if (finalError != null) { + if (finalError != null && state != STATE_REMOVING && state != STATE_RESTARTING) { failureReason = FAILURE_REASON_UNKNOWN; setState(STATE_FAILED); return; } + if (actionQueue.size() == 1) { + if (state == STATE_REMOVING) { + setState(STATE_REMOVED); + } else { + Assertions.checkState(state == STATE_DOWNLOADING); + setState(STATE_COMPLETED); + } + return; + } actionQueue.remove(); } - if (!actionQueue.isEmpty()) { - setActionAndUpdateState(actionQueue.peek()); - } else { - setState(STATE_COMPLETED); - } + initialize(/* restart= */ state == STATE_DOWNLOADING); } }