Commit 0ccda60a by olly Committed by Oliver Woodman

Support multiple DefaultDownloadIndex instances

PiperOrigin-RevId: 244226680
parent e9413b0d
...@@ -23,6 +23,7 @@ import android.database.sqlite.SQLiteException; ...@@ -23,6 +23,7 @@ import android.database.sqlite.SQLiteException;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import android.text.TextUtils;
import com.google.android.exoplayer2.database.DatabaseIOException; import com.google.android.exoplayer2.database.DatabaseIOException;
import com.google.android.exoplayer2.database.DatabaseProvider; import com.google.android.exoplayer2.database.DatabaseProvider;
import com.google.android.exoplayer2.database.VersionTable; import com.google.android.exoplayer2.database.VersionTable;
...@@ -32,18 +33,11 @@ import com.google.android.exoplayer2.util.Util; ...@@ -32,18 +33,11 @@ import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /** A {@link DownloadIndex} that uses SQLite to persist {@link Download Downloads}. */
* A {@link DownloadIndex} which uses SQLite to persist {@link Download}s.
*
* <p class="caution">Database access may take a long time, do not call methods of this class from
* the application main thread.
*/
public final class DefaultDownloadIndex implements WritableDownloadIndex { 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; @VisibleForTesting /* package */ static final int TABLE_VERSION = 1;
private static final String COLUMN_ID = "id"; private static final String COLUMN_ID = "id";
...@@ -108,11 +102,8 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { ...@@ -108,11 +102,8 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
COLUMN_UPDATE_TIME_MS COLUMN_UPDATE_TIME_MS
}; };
private static final String SQL_DROP_TABLE_IF_EXISTS = "DROP TABLE IF EXISTS " + TABLE_NAME; private static final String TABLE_SCHEMA =
private static final String SQL_CREATE_TABLE = "("
"CREATE TABLE "
+ TABLE_NAME
+ " ("
+ COLUMN_ID + COLUMN_ID
+ " TEXT PRIMARY KEY NOT NULL," + " TEXT PRIMARY KEY NOT NULL,"
+ COLUMN_TYPE + COLUMN_TYPE
...@@ -148,19 +139,42 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { ...@@ -148,19 +139,42 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
private static final String TRUE = "1"; private static final String TRUE = "1";
private final String name;
private final String tableName;
private final DatabaseProvider databaseProvider; private final DatabaseProvider databaseProvider;
private boolean initialized; private boolean initialized;
/** /**
* Creates a DefaultDownloadIndex which stores the {@link Download}s on a SQLite database provided * Creates an instance that stores the {@link Download Downloads} in an SQLite database provided
* by {@code databaseProvider}. * by a {@link DatabaseProvider}.
*
* <p>Equivalent to calling {@link #DefaultDownloadIndex(DatabaseProvider, String)} with {@code
* name=""}.
* *
* @param databaseProvider A DatabaseProvider which provides the database which will be used to * <p>Applications that only have one download index may use this constructor. Applications that
* store DownloadStatus table. * 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) { 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; this.databaseProvider = databaseProvider;
tableName = TABLE_PREFIX + name;
} }
@Override @Override
...@@ -207,7 +221,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { ...@@ -207,7 +221,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
values.put(COLUMN_UPDATE_TIME_MS, download.updateTimeMs); values.put(COLUMN_UPDATE_TIME_MS, download.updateTimeMs);
try { try {
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
writableDatabase.replaceOrThrow(TABLE_NAME, /* nullColumnHack= */ null, values); writableDatabase.replaceOrThrow(tableName, /* nullColumnHack= */ null, values);
} catch (SQLiteException e) { } catch (SQLiteException e) {
throw new DatabaseIOException(e); throw new DatabaseIOException(e);
} }
...@@ -217,7 +231,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { ...@@ -217,7 +231,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
public void removeDownload(String id) throws DatabaseIOException { public void removeDownload(String id) throws DatabaseIOException {
ensureInitialized(); ensureInitialized();
try { 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) { } catch (SQLiteException e) {
throw new DatabaseIOException(e); throw new DatabaseIOException(e);
} }
...@@ -230,7 +244,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { ...@@ -230,7 +244,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(COLUMN_STOP_REASON, stopReason); values.put(COLUMN_STOP_REASON, stopReason);
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); 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) { } catch (SQLException e) {
throw new DatabaseIOException(e); throw new DatabaseIOException(e);
} }
...@@ -244,7 +258,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { ...@@ -244,7 +258,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
values.put(COLUMN_STOP_REASON, stopReason); values.put(COLUMN_STOP_REASON, stopReason);
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
writableDatabase.update( 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) { } catch (SQLException e) {
throw new DatabaseIOException(e); throw new DatabaseIOException(e);
} }
...@@ -256,16 +270,15 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { ...@@ -256,16 +270,15 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
} }
try { try {
SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase(); SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase();
int version = int version = VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, name);
VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID);
if (version == VersionTable.VERSION_UNSET || version > TABLE_VERSION) { if (version == VersionTable.VERSION_UNSET || version > TABLE_VERSION) {
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
writableDatabase.beginTransaction(); writableDatabase.beginTransaction();
try { try {
VersionTable.setVersion( VersionTable.setVersion(
writableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID, TABLE_VERSION); writableDatabase, VersionTable.FEATURE_OFFLINE, name, TABLE_VERSION);
writableDatabase.execSQL(SQL_DROP_TABLE_IF_EXISTS); writableDatabase.execSQL("DROP TABLE IF EXISTS " + tableName);
writableDatabase.execSQL(SQL_CREATE_TABLE); writableDatabase.execSQL("CREATE TABLE " + tableName + " " + TABLE_SCHEMA);
writableDatabase.setTransactionSuccessful(); writableDatabase.setTransactionSuccessful();
} finally { } finally {
writableDatabase.endTransaction(); writableDatabase.endTransaction();
...@@ -287,7 +300,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { ...@@ -287,7 +300,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
return databaseProvider return databaseProvider
.getReadableDatabase() .getReadableDatabase()
.query( .query(
TABLE_NAME, tableName,
COLUMNS, COLUMNS,
selection, selection,
selectionArgs, selectionArgs,
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
*/ */
package com.google.android.exoplayer2.offline; 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 static com.google.common.truth.Truth.assertThat;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
...@@ -33,6 +32,8 @@ import org.junit.runner.RunWith; ...@@ -33,6 +32,8 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class DefaultDownloadIndexTest { public class DefaultDownloadIndexTest {
private static final String EMPTY_NAME = "singleton";
private ExoDatabaseProvider databaseProvider; private ExoDatabaseProvider databaseProvider;
private DefaultDownloadIndex downloadIndex; private DefaultDownloadIndex downloadIndex;
...@@ -170,14 +171,12 @@ public class DefaultDownloadIndexTest { ...@@ -170,14 +171,12 @@ public class DefaultDownloadIndexTest {
@Test @Test
public void putDownload_setsVersion() throws DatabaseIOException { public void putDownload_setsVersion() throws DatabaseIOException {
SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase(); SQLiteDatabase readableDatabase = databaseProvider.getReadableDatabase();
assertThat( assertThat(VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, EMPTY_NAME))
VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID))
.isEqualTo(VersionTable.VERSION_UNSET); .isEqualTo(VersionTable.VERSION_UNSET);
downloadIndex.putDownload(new DownloadBuilder("id1").build()); downloadIndex.putDownload(new DownloadBuilder("id1").build());
assertThat( assertThat(VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, EMPTY_NAME))
VersionTable.getVersion(readableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID))
.isEqualTo(DefaultDownloadIndex.TABLE_VERSION); .isEqualTo(DefaultDownloadIndex.TABLE_VERSION);
} }
...@@ -191,15 +190,14 @@ public class DefaultDownloadIndexTest { ...@@ -191,15 +190,14 @@ public class DefaultDownloadIndexTest {
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
VersionTable.setVersion( VersionTable.setVersion(
writableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID, Integer.MAX_VALUE); writableDatabase, VersionTable.FEATURE_OFFLINE, EMPTY_NAME, Integer.MAX_VALUE);
downloadIndex = new DefaultDownloadIndex(databaseProvider); downloadIndex = new DefaultDownloadIndex(databaseProvider);
cursor = downloadIndex.getDownloads(); cursor = downloadIndex.getDownloads();
assertThat(cursor.getCount()).isEqualTo(0); assertThat(cursor.getCount()).isEqualTo(0);
cursor.close(); cursor.close();
assertThat( assertThat(VersionTable.getVersion(writableDatabase, VersionTable.FEATURE_OFFLINE, EMPTY_NAME))
VersionTable.getVersion(writableDatabase, VersionTable.FEATURE_OFFLINE, INSTANCE_UID))
.isEqualTo(DefaultDownloadIndex.TABLE_VERSION); .isEqualTo(DefaultDownloadIndex.TABLE_VERSION);
} }
......
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