Make DownloadTracker use DownloadIndex
DownloadTracker will stop updating DownloadIndex when DownloadManager starts using the same DownloadIndex. PiperOrigin-RevId: 232306803
This commit is contained in:
parent
fb99c26426
commit
a5d64463c7
@ -18,7 +18,11 @@ package com.google.android.exoplayer2.demo;
|
|||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import com.google.android.exoplayer2.DefaultRenderersFactory;
|
import com.google.android.exoplayer2.DefaultRenderersFactory;
|
||||||
import com.google.android.exoplayer2.RenderersFactory;
|
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.DefaultDownloaderFactory;
|
||||||
|
import com.google.android.exoplayer2.offline.DownloadIndexUtil;
|
||||||
import com.google.android.exoplayer2.offline.DownloadManager;
|
import com.google.android.exoplayer2.offline.DownloadManager;
|
||||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
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.CacheDataSourceFactory;
|
||||||
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
|
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
|
||||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
||||||
|
import com.google.android.exoplayer2.util.Log;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Placeholder application to facilitate overriding Application methods for debugging and testing.
|
* Placeholder application to facilitate overriding Application methods for debugging and testing.
|
||||||
*/
|
*/
|
||||||
public class DemoApplication extends Application {
|
public class DemoApplication extends Application {
|
||||||
|
|
||||||
|
private static final String TAG = "DemoApplication";
|
||||||
private static final String DOWNLOAD_ACTION_FILE = "actions";
|
private static final String DOWNLOAD_ACTION_FILE = "actions";
|
||||||
private static final String DOWNLOAD_TRACKER_ACTION_FILE = "tracked_actions";
|
private static final String DOWNLOAD_TRACKER_ACTION_FILE = "tracked_actions";
|
||||||
private static final String DOWNLOAD_CONTENT_DIRECTORY = "downloads";
|
private static final String DOWNLOAD_CONTENT_DIRECTORY = "downloads";
|
||||||
@ -97,6 +104,16 @@ public class DemoApplication extends Application {
|
|||||||
|
|
||||||
private synchronized void initDownloadManager() {
|
private synchronized void initDownloadManager() {
|
||||||
if (downloadManager == null) {
|
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 =
|
DownloaderConstructorHelper downloaderConstructorHelper =
|
||||||
new DownloaderConstructorHelper(getDownloadCache(), buildHttpDataSourceFactory());
|
new DownloaderConstructorHelper(getDownloadCache(), buildHttpDataSourceFactory());
|
||||||
downloadManager =
|
downloadManager =
|
||||||
@ -108,10 +125,7 @@ public class DemoApplication extends Application {
|
|||||||
DownloadManager.DEFAULT_MIN_RETRY_COUNT,
|
DownloadManager.DEFAULT_MIN_RETRY_COUNT,
|
||||||
DownloadManager.DEFAULT_REQUIREMENTS);
|
DownloadManager.DEFAULT_REQUIREMENTS);
|
||||||
downloadTracker =
|
downloadTracker =
|
||||||
new DownloadTracker(
|
new DownloadTracker(/* context= */ this, buildDataSourceFactory(), downloadIndex);
|
||||||
/* context= */ this,
|
|
||||||
buildDataSourceFactory(),
|
|
||||||
new File(getDownloadDirectory(), DOWNLOAD_TRACKER_ACTION_FILE));
|
|
||||||
downloadManager.addListener(downloadTracker);
|
downloadManager.addListener(downloadTracker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,11 +34,13 @@ import android.widget.Toast;
|
|||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.RenderersFactory;
|
import com.google.android.exoplayer2.RenderersFactory;
|
||||||
import com.google.android.exoplayer2.offline.ActionFile;
|
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.DownloadAction;
|
||||||
import com.google.android.exoplayer2.offline.DownloadHelper;
|
import com.google.android.exoplayer2.offline.DownloadHelper;
|
||||||
import com.google.android.exoplayer2.offline.DownloadManager;
|
import com.google.android.exoplayer2.offline.DownloadManager;
|
||||||
import com.google.android.exoplayer2.offline.DownloadService;
|
import com.google.android.exoplayer2.offline.DownloadService;
|
||||||
import com.google.android.exoplayer2.offline.DownloadState;
|
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.offline.StreamKey;
|
||||||
import com.google.android.exoplayer2.scheduler.Requirements;
|
import com.google.android.exoplayer2.scheduler.Requirements;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
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.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.util.Log;
|
import com.google.android.exoplayer2.util.Log;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -80,20 +82,21 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
private final DataSource.Factory dataSourceFactory;
|
private final DataSource.Factory dataSourceFactory;
|
||||||
private final TrackNameProvider trackNameProvider;
|
private final TrackNameProvider trackNameProvider;
|
||||||
private final CopyOnWriteArraySet<Listener> listeners;
|
private final CopyOnWriteArraySet<Listener> listeners;
|
||||||
private final HashMap<Uri, DownloadAction> trackedDownloadStates;
|
private final HashMap<Uri, DownloadState> trackedDownloadStates;
|
||||||
private final ActionFile actionFile;
|
private final DefaultDownloadIndex downloadIndex;
|
||||||
private final Handler actionFileWriteHandler;
|
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.context = context.getApplicationContext();
|
||||||
this.dataSourceFactory = dataSourceFactory;
|
this.dataSourceFactory = dataSourceFactory;
|
||||||
this.actionFile = new ActionFile(actionFile);
|
this.downloadIndex = downloadIndex;
|
||||||
trackNameProvider = new DefaultTrackNameProvider(context.getResources());
|
trackNameProvider = new DefaultTrackNameProvider(context.getResources());
|
||||||
listeners = new CopyOnWriteArraySet<>();
|
listeners = new CopyOnWriteArraySet<>();
|
||||||
trackedDownloadStates = new HashMap<>();
|
trackedDownloadStates = new HashMap<>();
|
||||||
HandlerThread actionFileWriteThread = new HandlerThread("DownloadTracker");
|
HandlerThread actionFileWriteThread = new HandlerThread("DownloadTracker");
|
||||||
actionFileWriteThread.start();
|
actionFileWriteThread.start();
|
||||||
actionFileWriteHandler = new Handler(actionFileWriteThread.getLooper());
|
actionFileIOHandler = new Handler(actionFileWriteThread.getLooper());
|
||||||
loadTrackedActions();
|
loadTrackedActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +117,7 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
if (!trackedDownloadStates.containsKey(uri)) {
|
if (!trackedDownloadStates.containsKey(uri)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
return trackedDownloadStates.get(uri).getKeys();
|
return Arrays.asList(trackedDownloadStates.get(uri).streamKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleDownload(
|
public void toggleDownload(
|
||||||
@ -146,7 +149,7 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
|| downloadState.state == DownloadState.STATE_FAILED) {
|
|| downloadState.state == DownloadState.STATE_FAILED) {
|
||||||
// A download has been removed, or has failed. Stop tracking it.
|
// A download has been removed, or has failed. Stop tracking it.
|
||||||
if (trackedDownloadStates.remove(downloadState.uri) != null) {
|
if (trackedDownloadStates.remove(downloadState.uri) != null) {
|
||||||
handleTrackedDownloadStatesChanged();
|
handleTrackedDownloadStateChanged(downloadState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,27 +170,24 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
// Internal methods
|
// Internal methods
|
||||||
|
|
||||||
private void loadTrackedActions() {
|
private void loadTrackedActions() {
|
||||||
try {
|
DownloadStateCursor downloadStates = downloadIndex.getDownloadStates();
|
||||||
DownloadAction[] allActions = actionFile.load();
|
while (downloadStates.moveToNext()) {
|
||||||
for (DownloadAction action : allActions) {
|
DownloadState downloadState = downloadStates.getDownloadState();
|
||||||
trackedDownloadStates.put(action.uri, action);
|
trackedDownloadStates.put(downloadState.uri, downloadState);
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "Failed to load tracked actions", e);
|
|
||||||
}
|
}
|
||||||
|
downloadStates.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleTrackedDownloadStatesChanged() {
|
private void handleTrackedDownloadStateChanged(DownloadState downloadState) {
|
||||||
for (Listener listener : listeners) {
|
for (Listener listener : listeners) {
|
||||||
listener.onDownloadsChanged();
|
listener.onDownloadsChanged();
|
||||||
}
|
}
|
||||||
final DownloadAction[] actions = trackedDownloadStates.values().toArray(new DownloadAction[0]);
|
actionFileIOHandler.post(
|
||||||
actionFileWriteHandler.post(
|
|
||||||
() -> {
|
() -> {
|
||||||
try {
|
if (downloadState.state == DownloadState.STATE_REMOVED) {
|
||||||
actionFile.store(actions);
|
downloadIndex.removeDownloadState(downloadState.id);
|
||||||
} catch (IOException e) {
|
} else {
|
||||||
Log.e(TAG, "Failed to store tracked actions", e);
|
downloadIndex.putDownloadState(downloadState);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -197,8 +197,9 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
// This content is already being downloaded. Do nothing.
|
// This content is already being downloaded. Do nothing.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
trackedDownloadStates.put(action.uri, action);
|
DownloadState downloadState = new DownloadState(action);
|
||||||
handleTrackedDownloadStatesChanged();
|
trackedDownloadStates.put(downloadState.uri, downloadState);
|
||||||
|
handleTrackedDownloadStateChanged(downloadState);
|
||||||
startServiceWithAction(action);
|
startServiceWithAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ public final class DownloadIndexUtil {
|
|||||||
if (downloadState != null) {
|
if (downloadState != null) {
|
||||||
downloadState = merge(downloadState, action);
|
downloadState = merge(downloadState, action);
|
||||||
} else {
|
} else {
|
||||||
downloadState = convert(action);
|
downloadState = new DownloadState(action);
|
||||||
}
|
}
|
||||||
downloadIndex.putDownloadState(downloadState);
|
downloadIndex.putDownloadState(downloadState);
|
||||||
}
|
}
|
||||||
@ -121,26 +121,4 @@ public final class DownloadIndexUtil {
|
|||||||
newKeys,
|
newKeys,
|
||||||
action.data);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -164,6 +164,34 @@ public final class DownloadState {
|
|||||||
/** Not met requirements to download. */
|
/** Not met requirements to download. */
|
||||||
@Requirements.RequirementFlags public final int notMetRequirements;
|
@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(
|
/* package */ DownloadState(
|
||||||
String id,
|
String id,
|
||||||
String type,
|
String type,
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
package com.google.android.exoplayer2.offline;
|
package com.google.android.exoplayer2.offline;
|
||||||
|
|
||||||
/** Provides random read-write access to the result set returned by a database query. */
|
/** 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. */
|
/** Returns the DownloadState at the current position. */
|
||||||
DownloadState getDownloadState();
|
DownloadState getDownloadState();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user