Commit e13789bf by eguven Committed by Oliver Woodman

Hide internal DownloadManager states

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=188481259
parent a58bffbe
...@@ -16,12 +16,10 @@ ...@@ -16,12 +16,10 @@
package com.google.android.exoplayer2.offline; package com.google.android.exoplayer2.offline;
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_CANCELED; import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_CANCELED;
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_CANCELING;
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_ENDED; import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_ENDED;
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_ERROR; import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_ERROR;
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_QUEUED;
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_STARTED; import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_STARTED;
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_STOPPING;
import static com.google.android.exoplayer2.offline.DownloadManager.DownloadState.STATE_WAITING;
import android.os.ConditionVariable; import android.os.ConditionVariable;
import android.os.Handler; import android.os.Handler;
...@@ -31,7 +29,6 @@ import android.support.annotation.IntDef; ...@@ -31,7 +29,6 @@ import android.support.annotation.IntDef;
import android.util.Log; import android.util.Log;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.DownloadAction.Deserializer; import com.google.android.exoplayer2.offline.DownloadAction.Deserializer;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadState.State;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
...@@ -264,7 +261,7 @@ public final class DownloadManager { ...@@ -264,7 +261,7 @@ public final class DownloadManager {
return false; return false;
} }
for (int i = 0; i < tasks.size(); i++) { for (int i = 0; i < tasks.size(); i++) {
if (tasks.get(i).isRunning()) { if (tasks.get(i).isActive()) {
return false; return false;
} }
} }
...@@ -344,7 +341,7 @@ public final class DownloadManager { ...@@ -344,7 +341,7 @@ public final class DownloadManager {
return; return;
} }
logd("Task state is changed", downloadTask); logd("Task state is changed", downloadTask);
boolean stopped = !downloadTask.isRunning(); boolean stopped = !downloadTask.isActive();
if (stopped) { if (stopped) {
activeDownloadTasks.remove(downloadTask); activeDownloadTasks.remove(downloadTask);
} }
...@@ -446,62 +443,39 @@ public final class DownloadManager { ...@@ -446,62 +443,39 @@ public final class DownloadManager {
/** /**
* Task states. * Task states.
* *
* <p>Transition map (vertical states are source states): * <p>Transition diagram:
*
* <pre> * <pre>
* +-------+-------+-----+---------+--------+--------+-----+ * -> canceled
* |waiting|started|ended|canceling|canceled|stopping|error| * queued <-> started -> ended
* +---------+-------+-------+-----+---------+--------+--------+-----+ * -> error
* |waiting | | X | | X | | | |
* |started | | | X | X | | X | X |
* |canceling| | | | | X | | |
* |stopping | X | | | | | | |
* +---------+-------+-------+-----+---------+--------+--------+-----+
* </pre> * </pre>
*/ */
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({STATE_WAITING, STATE_STARTED, STATE_ENDED, STATE_CANCELING, STATE_CANCELED, @IntDef({STATE_QUEUED, STATE_STARTED, STATE_ENDED, STATE_CANCELED, STATE_ERROR})
STATE_STOPPING, STATE_ERROR})
public @interface State {} public @interface State {}
/** The task is waiting to be started. */ /** The task is waiting to be started. */
public static final int STATE_WAITING = 0; public static final int STATE_QUEUED = 0;
/** The task is currently started. */ /** The task is currently started. */
public static final int STATE_STARTED = 1; public static final int STATE_STARTED = 1;
/** The task completed. */ /** The task completed. */
public static final int STATE_ENDED = 2; public static final int STATE_ENDED = 2;
/** The task is about to be canceled. */
public static final int STATE_CANCELING = 3;
/** The task was canceled. */ /** The task was canceled. */
public static final int STATE_CANCELED = 4; public static final int STATE_CANCELED = 3;
/** The task is about to be stopped. */
public static final int STATE_STOPPING = 5;
/** The task failed. */ /** The task failed. */
public static final int STATE_ERROR = 6; public static final int STATE_ERROR = 4;
/** Returns whether the task is running. */
public static boolean isRunning(int state) {
return state == STATE_STARTED || state == STATE_STOPPING || state == STATE_CANCELING;
}
/** Returns whether the task is finished. */
public static boolean isFinished(int state) {
return state == STATE_ERROR || state == STATE_ENDED || state == STATE_CANCELED;
}
/** Returns the state string for the given state value. */ /** Returns the state string for the given state value. */
public static String getStateString(@State int state) { public static String getStateString(@State int state) {
switch (state) { switch (state) {
case STATE_WAITING: case STATE_QUEUED:
return "WAITING"; return "QUEUED";
case STATE_STARTED: case STATE_STARTED:
return "STARTED"; return "STARTED";
case STATE_ENDED: case STATE_ENDED:
return "ENDED"; return "ENDED";
case STATE_CANCELING:
return "CANCELING";
case STATE_CANCELED: case STATE_CANCELED:
return "CANCELED"; return "CANCELED";
case STATE_STOPPING:
return "STOPPING";
case STATE_ERROR: case STATE_ERROR:
return "ERROR"; return "ERROR";
default: default:
...@@ -531,7 +505,7 @@ public final class DownloadManager { ...@@ -531,7 +505,7 @@ public final class DownloadManager {
private DownloadState( private DownloadState(
int taskId, int taskId,
DownloadAction downloadAction, DownloadAction downloadAction,
int state, @State int state,
float downloadPercentage, float downloadPercentage,
long downloadedBytes, long downloadedBytes,
Throwable error) { Throwable error) {
...@@ -543,24 +517,51 @@ public final class DownloadManager { ...@@ -543,24 +517,51 @@ public final class DownloadManager {
this.error = error; this.error = error;
} }
/** Returns whether the task is finished. */
public boolean isFinished() {
return isFinished(state);
}
/** Returns whether the task is running. */
public boolean isRunning() {
return isRunning(state);
}
} }
private static final class DownloadTask implements Runnable { private static final class DownloadTask implements Runnable {
/**
* Task states.
*
* <p>Transition map (vertical states are source states):
*
* <pre>
* +------+-------+-----+-----------+-----------+--------+--------+-----+
* |queued|started|ended|q_canceling|s_canceling|canceled|stopping|error|
* +-----------+------+-------+-----+-----------+-----------+--------+--------+-----+
* |queued | | X | | X | | | | |
* |started | | | X | | X | | X | X |
* |q_canceling| | | | | | X | | |
* |s_canceling| | | | | | X | | |
* |stopping | X | | | | | | | |
* +-----------+------+-------+-----+-----------+-----------+--------+--------+-----+
* </pre>
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({
STATE_QUEUED,
STATE_STARTED,
STATE_ENDED,
STATE_CANCELED,
STATE_ERROR,
STATE_QUEUED_CANCELING,
STATE_STARTED_CANCELING,
STATE_STARTED_STOPPING
})
public @interface InternalState {}
/** The task is about to be canceled. */
public static final int STATE_QUEUED_CANCELING = 5;
/** The task is about to be canceled. */
public static final int STATE_STARTED_CANCELING = 6;
/** The task is about to be stopped. */
public static final int STATE_STARTED_STOPPING = 7;
private final int id; private final int id;
private final DownloadManager downloadManager; private final DownloadManager downloadManager;
private final DownloadAction downloadAction; private final DownloadAction downloadAction;
private final int minRetryCount; private final int minRetryCount;
private volatile @State int currentState; private volatile @InternalState int currentState;
private volatile Downloader downloader; private volatile Downloader downloader;
private Thread thread; private Thread thread;
private Throwable error; private Throwable error;
...@@ -570,28 +571,29 @@ public final class DownloadManager { ...@@ -570,28 +571,29 @@ public final class DownloadManager {
this.id = id; this.id = id;
this.downloadManager = downloadManager; this.downloadManager = downloadManager;
this.downloadAction = downloadAction; this.downloadAction = downloadAction;
this.currentState = STATE_WAITING; this.currentState = STATE_QUEUED;
this.minRetryCount = minRetryCount; this.minRetryCount = minRetryCount;
} }
public DownloadState getDownloadState() { public DownloadState getDownloadState() {
int externalState = getExternalState();
return new DownloadState( return new DownloadState(
id, downloadAction, currentState, getDownloadPercentage(), getDownloadedBytes(), error); id, downloadAction, externalState, getDownloadPercentage(), getDownloadedBytes(), error);
}
/** Returns the state of the task. */
public @State int getState() {
return currentState;
} }
/** Returns whether the task is finished. */ /** Returns whether the task is finished. */
public boolean isFinished() { public boolean isFinished() {
return DownloadState.isFinished(currentState); return currentState == STATE_ERROR
|| currentState == STATE_ENDED
|| currentState == STATE_CANCELED;
} }
/** Returns whether the task is running. */ /** Returns whether the task is started. */
public boolean isRunning() { public boolean isActive() {
return DownloadState.isRunning(currentState); return currentState == STATE_QUEUED_CANCELING
|| currentState == STATE_STARTED
|| currentState == STATE_STARTED_STOPPING
|| currentState == STATE_STARTED_CANCELING;
} }
/** /**
...@@ -621,52 +623,80 @@ public final class DownloadManager { ...@@ -621,52 +623,80 @@ public final class DownloadManager {
+ ' ' + ' '
+ downloadAction.getData() + downloadAction.getData()
+ ' ' + ' '
+ DownloadState.getStateString(currentState); + getStateString();
}
private String getStateString() {
switch (currentState) {
case STATE_QUEUED_CANCELING:
case STATE_STARTED_CANCELING:
return "CANCELING";
case STATE_STARTED_STOPPING:
return "STOPPING";
default:
return DownloadState.getStateString(currentState);
}
}
private int getExternalState() {
switch (currentState) {
case STATE_QUEUED_CANCELING:
return STATE_QUEUED;
case STATE_STARTED_CANCELING:
case STATE_STARTED_STOPPING:
return STATE_STARTED;
default:
return currentState;
}
} }
private void start() { private void start() {
if (changeStateAndNotify(STATE_WAITING, STATE_STARTED)) { if (changeStateAndNotify(STATE_QUEUED, STATE_STARTED)) {
thread = new Thread(this); thread = new Thread(this);
thread.start(); thread.start();
} }
} }
private boolean canStart() { private boolean canStart() {
return currentState == STATE_WAITING; return currentState == STATE_QUEUED;
} }
private void cancel() { private void cancel() {
if (changeStateAndNotify(STATE_WAITING, STATE_CANCELING)) { if (changeStateAndNotify(STATE_QUEUED, STATE_QUEUED_CANCELING)) {
downloadManager.handler.post(new Runnable() { downloadManager.handler.post(
new Runnable() {
@Override @Override
public void run() { public void run() {
changeStateAndNotify(STATE_CANCELING, STATE_CANCELED); changeStateAndNotify(STATE_QUEUED_CANCELING, STATE_CANCELED);
} }
}); });
} else if (changeStateAndNotify(STATE_STARTED, STATE_CANCELING)) { } else if (changeStateAndNotify(STATE_STARTED, STATE_STARTED_CANCELING)) {
thread.interrupt(); thread.interrupt();
} }
} }
private void stop() { private void stop() {
if (changeStateAndNotify(STATE_STARTED, STATE_STOPPING)) { if (changeStateAndNotify(STATE_STARTED, STATE_STARTED_STOPPING)) {
downloadManager.logd("Stopping", this); downloadManager.logd("Stopping", this);
thread.interrupt(); thread.interrupt();
} }
} }
private boolean changeStateAndNotify(@State int oldState, @State int newState) { private boolean changeStateAndNotify(@InternalState int oldState, @InternalState int newState) {
return changeStateAndNotify(oldState, newState, null); return changeStateAndNotify(oldState, newState, null);
} }
private boolean changeStateAndNotify(@State int oldState, @State int newState, private boolean changeStateAndNotify(
Throwable error) { @InternalState int oldState, @InternalState int newState, Throwable error) {
if (currentState != oldState) { if (currentState != oldState) {
return false; return false;
} }
currentState = newState; currentState = newState;
this.error = error; this.error = error;
boolean isInternalState = currentState != getExternalState();
if (!isInternalState) {
downloadManager.onTaskStateChange(DownloadTask.this); downloadManager.onTaskStateChange(DownloadTask.this);
}
return true; return true;
} }
...@@ -707,13 +737,14 @@ public final class DownloadManager { ...@@ -707,13 +737,14 @@ public final class DownloadManager {
error = e; error = e;
} }
final Throwable finalError = error; final Throwable finalError = error;
downloadManager.handler.post(new Runnable() { downloadManager.handler.post(
new Runnable() {
@Override @Override
public void run() { public void run() {
if (changeStateAndNotify(STATE_STARTED, if (changeStateAndNotify(
finalError != null ? STATE_ERROR : STATE_ENDED, finalError) STATE_STARTED, finalError != null ? STATE_ERROR : STATE_ENDED, finalError)
|| changeStateAndNotify(STATE_CANCELING, STATE_CANCELED) || changeStateAndNotify(STATE_STARTED_CANCELING, STATE_CANCELED)
|| changeStateAndNotify(STATE_STOPPING, STATE_WAITING)) { || changeStateAndNotify(STATE_STARTED_STOPPING, STATE_QUEUED)) {
return; return;
} }
throw new IllegalStateException(); throw new IllegalStateException();
......
...@@ -607,8 +607,7 @@ public class DownloadManagerTest { ...@@ -607,8 +607,7 @@ public class DownloadManagerTest {
} }
private FakeDownloadAction assertStopped() { private FakeDownloadAction assertStopped() {
assertState(DownloadState.STATE_STOPPING); return assertState(DownloadState.STATE_QUEUED);
return assertState(DownloadState.STATE_WAITING);
} }
private FakeDownloadAction assertState(@State int expectedState) { private FakeDownloadAction assertState(@State int expectedState) {
......
...@@ -67,12 +67,16 @@ public final class DownloadNotificationUtil { ...@@ -67,12 +67,16 @@ public final class DownloadNotificationUtil {
int titleStringId = getTitleStringId(downloadState); int titleStringId = getTitleStringId(downloadState);
notificationBuilder.setContentTitle(context.getResources().getString(titleStringId)); notificationBuilder.setContentTitle(context.getResources().getString(titleStringId));
if (downloadState.isRunning()) { if (downloadState.state == DownloadState.STATE_STARTED) {
notificationBuilder.setOngoing(true); notificationBuilder.setOngoing(true);
float percentage = downloadState.downloadPercentage; float percentage = downloadState.downloadPercentage;
boolean indeterminate = Float.isNaN(percentage); boolean indeterminate = Float.isNaN(percentage);
notificationBuilder.setProgress(100, indeterminate ? 0 : (int) percentage, indeterminate); notificationBuilder.setProgress(100, indeterminate ? 0 : (int) percentage, indeterminate);
} }
if (Util.SDK_INT >= 17) {
// Hide timestamp on the notification while download progresses.
notificationBuilder.setShowWhen(downloadState.state != DownloadState.STATE_STARTED);
}
if (downloadState.error != null && errorMessageProvider != null) { if (downloadState.error != null && errorMessageProvider != null) {
message = errorMessageProvider.getErrorMessage(downloadState.error).second; message = errorMessageProvider.getErrorMessage(downloadState.error).second;
...@@ -90,12 +94,10 @@ public final class DownloadNotificationUtil { ...@@ -90,12 +94,10 @@ public final class DownloadNotificationUtil {
private static int getTitleStringId(DownloadState downloadState) { private static int getTitleStringId(DownloadState downloadState) {
int titleStringId; int titleStringId;
switch (downloadState.state) { switch (downloadState.state) {
case DownloadState.STATE_WAITING: case DownloadState.STATE_QUEUED:
titleStringId = R.string.exo_download_queued; titleStringId = R.string.exo_download_queued;
break; break;
case DownloadState.STATE_STARTED: case DownloadState.STATE_STARTED:
case DownloadState.STATE_STOPPING:
case DownloadState.STATE_CANCELING:
titleStringId = R.string.exo_downloading; titleStringId = R.string.exo_downloading;
break; break;
case DownloadState.STATE_ENDED: case DownloadState.STATE_ENDED:
......
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