From a5d64463c781092f60664d9b86d9e0867dec0561 Mon Sep 17 00:00:00 2001 From: eguven Date: Mon, 4 Feb 2019 17:03:12 +0000 Subject: [PATCH] Make DownloadTracker use DownloadIndex DownloadTracker will stop updating DownloadIndex when DownloadManager starts using the same DownloadIndex. PiperOrigin-RevId: 232306803 --- .../exoplayer2/demo/DemoApplication.java | 22 ++++++-- .../exoplayer2/demo/DownloadTracker.java | 51 ++++++++++--------- .../exoplayer2/offline/DownloadIndexUtil.java | 24 +-------- .../exoplayer2/offline/DownloadState.java | 28 ++++++++++ .../offline/DownloadStateCursor.java | 2 +- 5 files changed, 74 insertions(+), 53 deletions(-) diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoApplication.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoApplication.java index 560a9be58a..27033bb03e 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoApplication.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoApplication.java @@ -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); } } diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DownloadTracker.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DownloadTracker.java index 83c8a76812..689e7241f7 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DownloadTracker.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DownloadTracker.java @@ -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 listeners; - private final HashMap trackedDownloadStates; - private final ActionFile actionFile; - private final Handler actionFileWriteHandler; + private final HashMap 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); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadIndexUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadIndexUtil.java index e0c914408b..0d6d2a36b5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadIndexUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadIndexUtil.java @@ -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); - } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadState.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadState.java index f5b3287b32..c59b7b87b6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadState.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadState.java @@ -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, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadStateCursor.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadStateCursor.java index 680976c77b..06511c8930 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadStateCursor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadStateCursor.java @@ -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();