From 0ccda60ab4d24c90b75aeab3983229512bee8fad Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 18 Apr 2019 19:34:00 +0100 Subject: [PATCH] Support multiple DefaultDownloadIndex instances PiperOrigin-RevId: 244226680 --- .../offline/DefaultDownloadIndex.java | 69 +++++++++++-------- .../offline/DefaultDownloadIndexTest.java | 14 ++-- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DefaultDownloadIndex.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DefaultDownloadIndex.java index a2caff3ff1..30297f19ce 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DefaultDownloadIndex.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DefaultDownloadIndex.java @@ -23,6 +23,7 @@ import android.database.sqlite.SQLiteException; import android.net.Uri; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import android.text.TextUtils; import com.google.android.exoplayer2.database.DatabaseIOException; import com.google.android.exoplayer2.database.DatabaseProvider; import com.google.android.exoplayer2.database.VersionTable; @@ -32,18 +33,11 @@ import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; import java.util.List; -/** - * A {@link DownloadIndex} which uses SQLite to persist {@link Download}s. - * - *

Database access may take a long time, do not call methods of this class from - * the application main thread. - */ +/** A {@link DownloadIndex} that uses SQLite to persist {@link Download Downloads}. */ public final class DefaultDownloadIndex implements WritableDownloadIndex { - private static final String TABLE_NAME = DatabaseProvider.TABLE_PREFIX + "Downloads"; + private static final String TABLE_PREFIX = DatabaseProvider.TABLE_PREFIX + "Downloads"; - // TODO: Support multiple instances. Probably using the underlying cache UID. - @VisibleForTesting /* package */ static final String INSTANCE_UID = "singleton"; @VisibleForTesting /* package */ static final int TABLE_VERSION = 1; private static final String COLUMN_ID = "id"; @@ -108,11 +102,8 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { COLUMN_UPDATE_TIME_MS }; - private static final String SQL_DROP_TABLE_IF_EXISTS = "DROP TABLE IF EXISTS " + TABLE_NAME; - private static final String SQL_CREATE_TABLE = - "CREATE TABLE " - + TABLE_NAME - + " (" + private static final String TABLE_SCHEMA = + "(" + COLUMN_ID + " TEXT PRIMARY KEY NOT NULL," + COLUMN_TYPE @@ -148,19 +139,42 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { private static final String TRUE = "1"; + private final String name; + private final String tableName; private final DatabaseProvider databaseProvider; private boolean initialized; /** - * Creates a DefaultDownloadIndex which stores the {@link Download}s on a SQLite database provided - * by {@code databaseProvider}. + * Creates an instance that stores the {@link Download Downloads} in an SQLite database provided + * by a {@link DatabaseProvider}. * - * @param databaseProvider A DatabaseProvider which provides the database which will be used to - * store DownloadStatus table. + *

Equivalent to calling {@link #DefaultDownloadIndex(DatabaseProvider, String)} with {@code + * name=""}. + * + *

Applications that only have one download index may use this constructor. Applications that + * have multiple download indices should call {@link #DefaultDownloadIndex(DatabaseProvider, + * String)} to specify a unique name for each index. + * + * @param databaseProvider Provides the SQLite database in which downloads are persisted. */ public DefaultDownloadIndex(DatabaseProvider databaseProvider) { + this(databaseProvider, ""); + } + + /** + * Creates an instance that stores the {@link Download Downloads} in an SQLite database provided + * by a {@link DatabaseProvider}. + * + * @param databaseProvider Provides the SQLite database in which downloads are persisted. + * @param name The name of the index. This name is incorporated into the names of the SQLite + * tables in which downloads are persisted. + */ + public DefaultDownloadIndex(DatabaseProvider databaseProvider, String name) { + // TODO: Remove this backward compatibility hack for launch. + this.name = TextUtils.isEmpty(name) ? "singleton" : name; this.databaseProvider = databaseProvider; + tableName = TABLE_PREFIX + name; } @Override @@ -207,7 +221,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { values.put(COLUMN_UPDATE_TIME_MS, download.updateTimeMs); try { SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); - writableDatabase.replaceOrThrow(TABLE_NAME, /* nullColumnHack= */ null, values); + writableDatabase.replaceOrThrow(tableName, /* nullColumnHack= */ null, values); } catch (SQLiteException e) { throw new DatabaseIOException(e); } @@ -217,7 +231,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { public void removeDownload(String id) throws DatabaseIOException { ensureInitialized(); try { - databaseProvider.getWritableDatabase().delete(TABLE_NAME, WHERE_ID_EQUALS, new String[] {id}); + databaseProvider.getWritableDatabase().delete(tableName, WHERE_ID_EQUALS, new String[] {id}); } catch (SQLiteException e) { throw new DatabaseIOException(e); } @@ -230,7 +244,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { ContentValues values = new ContentValues(); values.put(COLUMN_STOP_REASON, stopReason); SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); - writableDatabase.update(TABLE_NAME, values, WHERE_STATE_TERMINAL, /* whereArgs= */ null); + writableDatabase.update(tableName, values, WHERE_STATE_TERMINAL, /* whereArgs= */ null); } catch (SQLException e) { throw new DatabaseIOException(e); } @@ -244,7 +258,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { values.put(COLUMN_STOP_REASON, stopReason); SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); writableDatabase.update( - TABLE_NAME, values, WHERE_STATE_TERMINAL + " AND " + WHERE_ID_EQUALS, new String[] {id}); + tableName, values, WHERE_STATE_TERMINAL + " AND " + WHERE_ID_EQUALS, new String[] {id}); } catch (SQLException e) { throw new DatabaseIOException(e); } @@ -256,16 +270,15 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { } try { SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase(); - int version = - VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID); + int version = VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, name); if (version == VersionTable.VERSION_UNSET || version > TABLE_VERSION) { SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); writableDatabase.beginTransaction(); try { VersionTable.setVersion( - writableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID, TABLE_VERSION); - writableDatabase.execSQL(SQL_DROP_TABLE_IF_EXISTS); - writableDatabase.execSQL(SQL_CREATE_TABLE); + writableDatabase, VersionTable.FEATURE_OFFLINE, name, TABLE_VERSION); + writableDatabase.execSQL("DROP TABLE IF EXISTS " + tableName); + writableDatabase.execSQL("CREATE TABLE " + tableName + " " + TABLE_SCHEMA); writableDatabase.setTransactionSuccessful(); } finally { writableDatabase.endTransaction(); @@ -287,7 +300,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { return databaseProvider .getReadableDatabase() .query( - TABLE_NAME, + tableName, COLUMNS, selection, selectionArgs, diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/DefaultDownloadIndexTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/DefaultDownloadIndexTest.java index a426a7488b..73c73b6647 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/offline/DefaultDownloadIndexTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/DefaultDownloadIndexTest.java @@ -15,7 +15,6 @@ */ package com.google.android.exoplayer2.offline; -import static com.google.android.exoplayer2.offline.DefaultDownloadIndex.INSTANCE_UID; import static com.google.common.truth.Truth.assertThat; import android.database.sqlite.SQLiteDatabase; @@ -33,6 +32,8 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class DefaultDownloadIndexTest { + private static final String EMPTY_NAME = "singleton"; + private ExoDatabaseProvider databaseProvider; private DefaultDownloadIndex downloadIndex; @@ -170,14 +171,12 @@ public class DefaultDownloadIndexTest { @Test public void putDownload_setsVersion() throws DatabaseIOException { SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase(); - assertThat( - VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID)) + assertThat(VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, EMPTY_NAME)) .isEqualTo(VersionTable.VERSION_UNSET); downloadIndex.putDownload(new DownloadBuilder("id1").build()); - assertThat( - VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID)) + assertThat(VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, EMPTY_NAME)) .isEqualTo(DefaultDownloadIndex.TABLE_VERSION); } @@ -191,15 +190,14 @@ public class DefaultDownloadIndexTest { SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); VersionTable.setVersion( - writableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID, Integer.MAX_VALUE); + writableDatabase, VersionTable.FEATURE_OFFLINE, EMPTY_NAME, Integer.MAX_VALUE); downloadIndex = new DefaultDownloadIndex(databaseProvider); cursor = downloadIndex.getDownloads(); assertThat(cursor.getCount()).isEqualTo(0); cursor.close(); - assertThat( - VersionTable.getVersion(writableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID)) + assertThat(VersionTable.getVersion(writableDatabase, VersionTable.FEATURE_OFFLINE, EMPTY_NAME)) .isEqualTo(DefaultDownloadIndex.TABLE_VERSION); }