Make DownloadTracker use DownloadIndex

DownloadTracker will stop updating DownloadIndex when DownloadManager
starts using the same DownloadIndex.

PiperOrigin-RevId: 232306803
This commit is contained in:
eguven 2019-02-04 17:03:12 +00:00 committed by Oliver Woodman
parent fb99c26426
commit a5d64463c7
5 changed files with 74 additions and 53 deletions

View File

@ -18,7 +18,11 @@ package com.google.android.exoplayer2.demo;
import android.app.Application;
import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
import com.google.android.exoplayer2.offline.ActionFile;
import com.google.android.exoplayer2.offline.DefaultDownloadIndex;
import com.google.android.exoplayer2.offline.DefaultDownloaderFactory;
import com.google.android.exoplayer2.offline.DownloadIndexUtil;
import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.upstream.DataSource;
@ -31,14 +35,17 @@ import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory;
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util;
import java.io.File;
import java.io.IOException;
/**
* Placeholder application to facilitate overriding Application methods for debugging and testing.
*/
public class DemoApplication extends Application {
private static final String TAG = "DemoApplication";
private static final String DOWNLOAD_ACTION_FILE = "actions";
private static final String DOWNLOAD_TRACKER_ACTION_FILE = "tracked_actions";
private static final String DOWNLOAD_CONTENT_DIRECTORY = "downloads";
@ -97,6 +104,16 @@ public class DemoApplication extends Application {
private synchronized void initDownloadManager() {
if (downloadManager == null) {
DefaultDownloadIndex downloadIndex = new DefaultDownloadIndex(new ExoDatabaseProvider(this));
File actionFile = new File(getDownloadDirectory(), DOWNLOAD_TRACKER_ACTION_FILE);
if (actionFile.exists()) {
try {
DownloadIndexUtil.upgradeActionFile(new ActionFile(actionFile), downloadIndex, null);
} catch (IOException e) {
Log.e(TAG, "Upgrading action file failed", e);
}
actionFile.delete();
}
DownloaderConstructorHelper downloaderConstructorHelper =
new DownloaderConstructorHelper(getDownloadCache(), buildHttpDataSourceFactory());
downloadManager =
@ -108,10 +125,7 @@ public class DemoApplication extends Application {
DownloadManager.DEFAULT_MIN_RETRY_COUNT,
DownloadManager.DEFAULT_REQUIREMENTS);
downloadTracker =
new DownloadTracker(
/* context= */ this,
buildDataSourceFactory(),
new File(getDownloadDirectory(), DOWNLOAD_TRACKER_ACTION_FILE));
new DownloadTracker(/* context= */ this, buildDataSourceFactory(), downloadIndex);
downloadManager.addListener(downloadTracker);
}
}

View File

@ -34,11 +34,13 @@ import android.widget.Toast;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.offline.ActionFile;
import com.google.android.exoplayer2.offline.DefaultDownloadIndex;
import com.google.android.exoplayer2.offline.DownloadAction;
import com.google.android.exoplayer2.offline.DownloadHelper;
import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadService;
import com.google.android.exoplayer2.offline.DownloadState;
import com.google.android.exoplayer2.offline.DownloadStateCursor;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.source.TrackGroupArray;
@ -51,8 +53,8 @@ import com.google.android.exoplayer2.ui.TrackSelectionView;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@ -80,20 +82,21 @@ public class DownloadTracker implements DownloadManager.Listener {
private final DataSource.Factory dataSourceFactory;
private final TrackNameProvider trackNameProvider;
private final CopyOnWriteArraySet<Listener> listeners;
private final HashMap<Uri, DownloadAction> trackedDownloadStates;
private final ActionFile actionFile;
private final Handler actionFileWriteHandler;
private final HashMap<Uri, DownloadState> trackedDownloadStates;
private final DefaultDownloadIndex downloadIndex;
private final Handler actionFileIOHandler;
public DownloadTracker(Context context, DataSource.Factory dataSourceFactory, File actionFile) {
public DownloadTracker(
Context context, DataSource.Factory dataSourceFactory, DefaultDownloadIndex downloadIndex) {
this.context = context.getApplicationContext();
this.dataSourceFactory = dataSourceFactory;
this.actionFile = new ActionFile(actionFile);
this.downloadIndex = downloadIndex;
trackNameProvider = new DefaultTrackNameProvider(context.getResources());
listeners = new CopyOnWriteArraySet<>();
trackedDownloadStates = new HashMap<>();
HandlerThread actionFileWriteThread = new HandlerThread("DownloadTracker");
actionFileWriteThread.start();
actionFileWriteHandler = new Handler(actionFileWriteThread.getLooper());
actionFileIOHandler = new Handler(actionFileWriteThread.getLooper());
loadTrackedActions();
}
@ -114,7 +117,7 @@ public class DownloadTracker implements DownloadManager.Listener {
if (!trackedDownloadStates.containsKey(uri)) {
return Collections.emptyList();
}
return trackedDownloadStates.get(uri).getKeys();
return Arrays.asList(trackedDownloadStates.get(uri).streamKeys);
}
public void toggleDownload(
@ -146,7 +149,7 @@ public class DownloadTracker implements DownloadManager.Listener {
|| downloadState.state == DownloadState.STATE_FAILED) {
// A download has been removed, or has failed. Stop tracking it.
if (trackedDownloadStates.remove(downloadState.uri) != null) {
handleTrackedDownloadStatesChanged();
handleTrackedDownloadStateChanged(downloadState);
}
}
}
@ -167,27 +170,24 @@ public class DownloadTracker implements DownloadManager.Listener {
// Internal methods
private void loadTrackedActions() {
try {
DownloadAction[] allActions = actionFile.load();
for (DownloadAction action : allActions) {
trackedDownloadStates.put(action.uri, action);
}
} catch (IOException e) {
Log.e(TAG, "Failed to load tracked actions", e);
DownloadStateCursor downloadStates = downloadIndex.getDownloadStates();
while (downloadStates.moveToNext()) {
DownloadState downloadState = downloadStates.getDownloadState();
trackedDownloadStates.put(downloadState.uri, downloadState);
}
downloadStates.close();
}
private void handleTrackedDownloadStatesChanged() {
private void handleTrackedDownloadStateChanged(DownloadState downloadState) {
for (Listener listener : listeners) {
listener.onDownloadsChanged();
}
final DownloadAction[] actions = trackedDownloadStates.values().toArray(new DownloadAction[0]);
actionFileWriteHandler.post(
actionFileIOHandler.post(
() -> {
try {
actionFile.store(actions);
} catch (IOException e) {
Log.e(TAG, "Failed to store tracked actions", e);
if (downloadState.state == DownloadState.STATE_REMOVED) {
downloadIndex.removeDownloadState(downloadState.id);
} else {
downloadIndex.putDownloadState(downloadState);
}
});
}
@ -197,8 +197,9 @@ public class DownloadTracker implements DownloadManager.Listener {
// This content is already being downloaded. Do nothing.
return;
}
trackedDownloadStates.put(action.uri, action);
handleTrackedDownloadStatesChanged();
DownloadState downloadState = new DownloadState(action);
trackedDownloadStates.put(downloadState.uri, downloadState);
handleTrackedDownloadStateChanged(downloadState);
startServiceWithAction(action);
}

View File

@ -81,7 +81,7 @@ public final class DownloadIndexUtil {
if (downloadState != null) {
downloadState = merge(downloadState, action);
} else {
downloadState = convert(action);
downloadState = new DownloadState(action);
}
downloadIndex.putDownloadState(downloadState);
}
@ -121,26 +121,4 @@ public final class DownloadIndexUtil {
newKeys,
action.data);
}
private static DownloadState convert(DownloadAction action) {
long currentTimeMs = System.currentTimeMillis();
return new DownloadState(
action.id,
action.type,
action.uri,
action.customCacheKey,
/* state= */ action.isRemoveAction
? DownloadState.STATE_REMOVING
: DownloadState.STATE_QUEUED,
/* downloadPercentage= */ C.PERCENTAGE_UNSET,
/* downloadedBytes= */ 0,
/* totalBytes= */ C.LENGTH_UNSET,
DownloadState.FAILURE_REASON_NONE,
/* stopFlags= */ 0,
/* notMetRequirements= */ 0,
/* startTimeMs= */ currentTimeMs,
/* updateTimeMs= */ currentTimeMs,
action.keys.toArray(new StreamKey[0]),
action.data);
}
}

View File

@ -164,6 +164,34 @@ public final class DownloadState {
/** Not met requirements to download. */
@Requirements.RequirementFlags public final int notMetRequirements;
/**
* Creates a {@link DownloadState} using a {@link DownloadAction}.
*
* @param action The {@link DownloadAction}.
*/
public DownloadState(DownloadAction action) {
this(action, System.currentTimeMillis());
}
private DownloadState(DownloadAction action, long currentTimeMs) {
this(
action.id,
action.type,
action.uri,
action.customCacheKey,
/* state= */ action.isRemoveAction ? STATE_REMOVING : STATE_QUEUED,
/* downloadPercentage= */ C.PERCENTAGE_UNSET,
/* downloadedBytes= */ 0,
/* totalBytes= */ C.LENGTH_UNSET,
FAILURE_REASON_NONE,
/* stopFlags= */ 0,
/* notMetRequirements= */ 0,
/* startTimeMs= */ currentTimeMs,
/* updateTimeMs= */ currentTimeMs,
action.keys.toArray(new StreamKey[0]),
action.data);
}
/* package */ DownloadState(
String id,
String type,

View File

@ -16,7 +16,7 @@
package com.google.android.exoplayer2.offline;
/** Provides random read-write access to the result set returned by a database query. */
interface DownloadStateCursor {
public interface DownloadStateCursor {
/** Returns the DownloadState at the current position. */
DownloadState getDownloadState();