aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRahul Ravikumar <rahulrav@google.com>2018-07-10 10:35:10 -0700
committerandroid-build-merger <android-build-merger@google.com>2018-07-10 10:35:10 -0700
commite74a0e388018f7d217bd2a6efc73bede96dcd64a (patch)
tree1fa604cc39cd608146aa60c143ae29d2c1279994
parent3a4f96a54a38157aadcafb1be0b179fc2a00bdaa (diff)
parentca2810524b51260f0bdb7cfde3e8038d9abc6d44 (diff)
downloadsupport-pie-qpr1-release.tar.gz
am: ca2810524b Change-Id: I79ad375291edf687522e48c6502d583ee8a211af
-rw-r--r--work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java116
-rw-r--r--work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java3
-rw-r--r--work/workmanager/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java1
-rw-r--r--work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java12
-rw-r--r--work/workmanager/src/main/java/androidx/work/impl/WorkDatabaseMigrations.java37
-rw-r--r--work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java14
-rw-r--r--work/workmanager/src/main/java/androidx/work/impl/model/WorkSpec.java8
-rw-r--r--work/workmanager/src/schemas/androidx.work.impl.WorkDatabase/4.json363
8 files changed, 510 insertions, 44 deletions
diff --git a/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java b/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java
index 4e62cedb677..0cba3cf0c6c 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java
@@ -18,6 +18,12 @@ package androidx.work;
import static android.database.sqlite.SQLiteDatabase.CONFLICT_FAIL;
+import static androidx.work.impl.WorkDatabaseMigrations.MIGRATION_3_4;
+import static androidx.work.impl.WorkDatabaseMigrations.VERSION_1;
+import static androidx.work.impl.WorkDatabaseMigrations.VERSION_2;
+import static androidx.work.impl.WorkDatabaseMigrations.VERSION_3;
+import static androidx.work.impl.WorkDatabaseMigrations.VERSION_4;
+
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -28,12 +34,15 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
+import android.os.Build;
+import android.support.annotation.NonNull;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import androidx.work.impl.WorkDatabase;
import androidx.work.impl.WorkDatabaseMigrations;
+import androidx.work.impl.WorkManagerImpl;
import androidx.work.impl.model.WorkSpec;
import androidx.work.impl.model.WorkTypeConverters;
import androidx.work.impl.utils.Preferences;
@@ -53,9 +62,6 @@ public class WorkDatabaseMigrationTest {
private static final String TEST_DATABASE = "workdatabase-test";
private static final boolean VALIDATE_DROPPED_TABLES = true;
- private static final int VERSION_1 = 1;
- private static final int VERSION_2 = 2;
- private static final int VERSION_3 = 3;
private static final String COLUMN_WORKSPEC_ID = "work_spec_id";
private static final String COLUMN_SYSTEM_ID = "system_id";
private static final String COLUMN_ALARM_ID = "alarm_id";
@@ -97,35 +103,12 @@ public class WorkDatabaseMigrationTest {
SupportSQLiteDatabase database =
mMigrationTestHelper.createDatabase(TEST_DATABASE, VERSION_1);
- String[] prepopulatedWorkSpecIds = new String[] {
+ String[] prepopulatedWorkSpecIds = new String[]{
UUID.randomUUID().toString(),
UUID.randomUUID().toString()
};
for (String workSpecId : prepopulatedWorkSpecIds) {
- ContentValues contentValues = new ContentValues();
- contentValues.put("id", workSpecId);
- contentValues.put("state", WorkTypeConverters.StateIds.ENQUEUED);
- contentValues.put("worker_class_name", TestWorker.class.getName());
- contentValues.put("input_merger_class_name", OverwritingInputMerger.class.getName());
- contentValues.put("input", Data.toByteArray(Data.EMPTY));
- contentValues.put("output", Data.toByteArray(Data.EMPTY));
- contentValues.put("initial_delay", 0L);
- contentValues.put("interval_duration", 0L);
- contentValues.put("flex_duration", 0L);
- contentValues.put("required_network_type", false);
- contentValues.put("requires_charging", false);
- contentValues.put("requires_device_idle", false);
- contentValues.put("requires_battery_not_low", false);
- contentValues.put("requires_storage_not_low", false);
- contentValues.put("content_uri_triggers",
- WorkTypeConverters.contentUriTriggersToByteArray(new ContentUriTriggers()));
- contentValues.put("run_attempt_count", 0);
- contentValues.put("backoff_policy",
- WorkTypeConverters.backoffPolicyToInt(BackoffPolicy.EXPONENTIAL));
- contentValues.put("backoff_delay_duration", WorkRequest.DEFAULT_BACKOFF_DELAY_MILLIS);
- contentValues.put("period_start_time", 0L);
- contentValues.put("minimum_retention_duration", 0L);
- contentValues.put("schedule_requested_at", WorkSpec.SCHEDULE_NOT_REQUESTED_YET);
+ ContentValues contentValues = contentValues(workSpecId);
database.insert("workspec", CONFLICT_FAIL, contentValues);
if (workSpecId.equals(prepopulatedWorkSpecIds[0])) {
@@ -193,8 +176,8 @@ public class WorkDatabaseMigrationTest {
public void testMigrationVersion2To3() throws IOException {
SupportSQLiteDatabase database =
mMigrationTestHelper.createDatabase(TEST_DATABASE, VERSION_2);
- WorkDatabaseMigrations.Migration2To3 migration2To3 = new WorkDatabaseMigrations
- .Migration2To3(mContext);
+ WorkDatabaseMigrations.WorkMigration migration2To3 =
+ new WorkDatabaseMigrations.WorkMigration(mContext, VERSION_2, VERSION_3);
database = mMigrationTestHelper.runMigrationsAndValidate(
TEST_DATABASE,
@@ -207,6 +190,79 @@ public class WorkDatabaseMigrationTest {
database.close();
}
+ @Test
+ @MediumTest
+ public void testMigrationVersion3To4() throws IOException {
+ SupportSQLiteDatabase database =
+ mMigrationTestHelper.createDatabase(TEST_DATABASE, VERSION_3);
+
+ String oneTimeWorkSpecId = UUID.randomUUID().toString();
+ long scheduleRequestedAt = System.currentTimeMillis();
+ ContentValues oneTimeWorkSpecContentValues = contentValues(oneTimeWorkSpecId);
+ oneTimeWorkSpecContentValues.put("schedule_requested_at", scheduleRequestedAt);
+
+ String periodicWorkSpecId = UUID.randomUUID().toString();
+ ContentValues periodicWorkSpecContentValues = contentValues(periodicWorkSpecId);
+ periodicWorkSpecContentValues.put("interval_duration", 15 * 60 * 1000L);
+
+ database.insert("workspec", CONFLICT_FAIL, oneTimeWorkSpecContentValues);
+ database.insert("workspec", CONFLICT_FAIL, periodicWorkSpecContentValues);
+
+ database = mMigrationTestHelper.runMigrationsAndValidate(
+ TEST_DATABASE,
+ VERSION_4,
+ VALIDATE_DROPPED_TABLES,
+ MIGRATION_3_4);
+
+ Cursor cursor = database.query("SELECT * from workspec");
+ assertThat(cursor.getCount(), is(2));
+ cursor.moveToFirst();
+ assertThat(cursor.getString(cursor.getColumnIndex("id")),
+ is(oneTimeWorkSpecId));
+ assertThat(cursor.getLong(cursor.getColumnIndex("schedule_requested_at")),
+ is(scheduleRequestedAt));
+ cursor.moveToNext();
+ assertThat(cursor.getString(cursor.getColumnIndex("id")),
+ is(periodicWorkSpecId));
+ if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) {
+ assertThat(cursor.getLong(cursor.getColumnIndex("schedule_requested_at")),
+ is(0L));
+ } else {
+ assertThat(cursor.getLong(cursor.getColumnIndex("schedule_requested_at")),
+ is(WorkSpec.SCHEDULE_NOT_REQUESTED_YET));
+ }
+ database.close();
+ }
+
+ @NonNull
+ private ContentValues contentValues(String workSpecId) {
+ ContentValues contentValues = new ContentValues();
+ contentValues.put("id", workSpecId);
+ contentValues.put("state", WorkTypeConverters.StateIds.ENQUEUED);
+ contentValues.put("worker_class_name", TestWorker.class.getName());
+ contentValues.put("input_merger_class_name", OverwritingInputMerger.class.getName());
+ contentValues.put("input", Data.toByteArray(Data.EMPTY));
+ contentValues.put("output", Data.toByteArray(Data.EMPTY));
+ contentValues.put("initial_delay", 0L);
+ contentValues.put("interval_duration", 0L);
+ contentValues.put("flex_duration", 0L);
+ contentValues.put("required_network_type", false);
+ contentValues.put("requires_charging", false);
+ contentValues.put("requires_device_idle", false);
+ contentValues.put("requires_battery_not_low", false);
+ contentValues.put("requires_storage_not_low", false);
+ contentValues.put("content_uri_triggers",
+ WorkTypeConverters.contentUriTriggersToByteArray(new ContentUriTriggers()));
+ contentValues.put("run_attempt_count", 0);
+ contentValues.put("backoff_policy",
+ WorkTypeConverters.backoffPolicyToInt(BackoffPolicy.EXPONENTIAL));
+ contentValues.put("backoff_delay_duration", WorkRequest.DEFAULT_BACKOFF_DELAY_MILLIS);
+ contentValues.put("period_start_time", 0L);
+ contentValues.put("minimum_retention_duration", 0L);
+ contentValues.put("schedule_requested_at", WorkSpec.SCHEDULE_NOT_REQUESTED_YET);
+ return contentValues;
+ }
+
private boolean checkExists(SupportSQLiteDatabase database, String tableName) {
Cursor cursor = null;
try {
diff --git a/work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java b/work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
index 8e54d072cc5..4e1dc8fa8c7 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
@@ -27,6 +27,7 @@ import static androidx.work.State.ENQUEUED;
import static androidx.work.State.FAILED;
import static androidx.work.State.RUNNING;
import static androidx.work.State.SUCCEEDED;
+import static androidx.work.impl.model.WorkSpec.SCHEDULE_NOT_REQUESTED_YET;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
@@ -1405,7 +1406,7 @@ public class WorkManagerImplTest {
WorkDatabase.generateCleanupCallback().onOpen(db);
assertThat(workSpecDao.getState(work.getStringId()), is(ENQUEUED));
- assertThat(work.getWorkSpec().scheduleRequestedAt, is(WorkSpec.SCHEDULE_NOT_REQUESTED_YET));
+ assertThat(work.getWorkSpec().scheduleRequestedAt, is(SCHEDULE_NOT_REQUESTED_YET));
}
@Test
diff --git a/work/workmanager/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java b/work/workmanager/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java
index c9a8e64c469..44e65f808f9 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java
@@ -517,7 +517,6 @@ public class WorkerWrapperTest extends DatabaseTest {
verify(mMockListener).onExecuted(periodicWorkId, true, false);
assertThat(periodicWorkSpecAfterFirstRun.runAttemptCount, is(0));
assertThat(periodicWorkSpecAfterFirstRun.state, is(ENQUEUED));
-
// SystemAlarmScheduler needs to reschedule the same worker.
if (Build.VERSION.SDK_INT <= WorkManagerImpl.MAX_PRE_JOB_SCHEDULER_API_LEVEL) {
ArgumentCaptor<WorkSpec> captor = ArgumentCaptor.forClass(WorkSpec.class);
diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java
index bd6ca33eb6f..b8bc72c3119 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java
@@ -16,6 +16,9 @@
package androidx.work.impl;
+import static androidx.work.impl.WorkDatabaseMigrations.MIGRATION_3_4;
+import static androidx.work.impl.WorkDatabaseMigrations.VERSION_2;
+import static androidx.work.impl.WorkDatabaseMigrations.VERSION_3;
import static androidx.work.impl.model.WorkTypeConverters.StateIds.COMPLETED_STATES;
import static androidx.work.impl.model.WorkTypeConverters.StateIds.ENQUEUED;
import static androidx.work.impl.model.WorkTypeConverters.StateIds.RUNNING;
@@ -56,7 +59,7 @@ import java.util.concurrent.TimeUnit;
WorkTag.class,
SystemIdInfo.class,
WorkName.class},
- version = 3)
+ version = 4)
@TypeConverters(value = {Data.class, WorkTypeConverters.class})
public abstract class WorkDatabase extends RoomDatabase {
@@ -84,7 +87,7 @@ public abstract class WorkDatabase extends RoomDatabase {
/**
* Creates an instance of the WorkDatabase.
*
- * @param context A context (this method will use the application context from it)
+ * @param context A context (this method will use the application context from it)
* @param useTestDatabase {@code true} to generate an in-memory database that allows main thread
* access
* @return The created WorkDatabase
@@ -97,9 +100,12 @@ public abstract class WorkDatabase extends RoomDatabase {
} else {
builder = Room.databaseBuilder(context, WorkDatabase.class, DB_NAME);
}
+
return builder.addCallback(generateCleanupCallback())
.addMigrations(WorkDatabaseMigrations.MIGRATION_1_2)
- .addMigrations(new WorkDatabaseMigrations.Migration2To3(context))
+ .addMigrations(
+ new WorkDatabaseMigrations.WorkMigration(context, VERSION_2, VERSION_3))
+ .addMigrations(MIGRATION_3_4)
.fallbackToDestructiveMigration()
.build();
}
diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabaseMigrations.java b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabaseMigrations.java
index 86d503deb4c..d75b51473ea 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabaseMigrations.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabaseMigrations.java
@@ -19,9 +19,12 @@ package androidx.work.impl;
import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.room.migration.Migration;
import android.content.Context;
+import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.RestrictTo;
+import androidx.work.impl.model.WorkSpec;
+import androidx.work.impl.model.WorkTypeConverters;
import androidx.work.impl.utils.Preferences;
/**
@@ -37,9 +40,10 @@ public class WorkDatabaseMigrations {
}
// Known WorkDatabase versions
- private static final int VERSION_1 = 1;
- private static final int VERSION_2 = 2;
- private static final int VERSION_3 = 3;
+ public static final int VERSION_1 = 1;
+ public static final int VERSION_2 = 2;
+ public static final int VERSION_3 = 3;
+ public static final int VERSION_4 = 4;
private static final String CREATE_SYSTEM_ID_INFO =
"CREATE TABLE IF NOT EXISTS `SystemIdInfo` (`work_spec_id` TEXT NOT NULL, `system_id`"
@@ -50,6 +54,12 @@ public class WorkDatabaseMigrations {
"INSERT INTO SystemIdInfo(work_spec_id, system_id) "
+ "SELECT work_spec_id, alarm_id AS system_id FROM alarmInfo";
+ private static final String PERIODIC_WORK_SET_SCHEDULE_REQUESTED_AT =
+ "UPDATE workspec SET schedule_requested_at=0"
+ + " WHERE state NOT IN " + WorkTypeConverters.StateIds.COMPLETED_STATES
+ + " AND schedule_requested_at=" + WorkSpec.SCHEDULE_NOT_REQUESTED_YET
+ + " AND interval_duration<>0";
+
private static final String REMOVE_ALARM_INFO = "DROP TABLE IF EXISTS alarmInfo";
/**
@@ -69,13 +79,13 @@ public class WorkDatabaseMigrations {
};
/**
- * Migrates {@link WorkDatabase} version 2 to 3.
+ * A {@link WorkDatabase} migration that reschedules all eligible Workers.
*/
- public static class Migration2To3 extends Migration {
+ public static class WorkMigration extends Migration {
final Context mContext;
- public Migration2To3(@NonNull Context context) {
- super(VERSION_2, VERSION_3);
+ public WorkMigration(@NonNull Context context, int startVersion, int endVersion) {
+ super(startVersion, endVersion);
mContext = context;
}
@@ -85,4 +95,17 @@ public class WorkDatabaseMigrations {
preferences.setNeedsReschedule(true);
}
}
+
+ /**
+ * Marks {@code SCHEDULE_REQUESTED_AT} to something other than
+ * {@code SCHEDULE_NOT_REQUESTED_AT}.
+ */
+ public static Migration MIGRATION_3_4 = new Migration(VERSION_3, VERSION_4) {
+ @Override
+ public void migrate(@NonNull SupportSQLiteDatabase database) {
+ if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) {
+ database.execSQL(PERIODIC_WORK_SET_SCHEDULE_REQUESTED_AT);
+ }
+ }
+ };
}
diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java b/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java
index ef1214c9ea4..87f922fc6bb 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java
@@ -21,6 +21,7 @@ import static androidx.work.State.ENQUEUED;
import static androidx.work.State.FAILED;
import static androidx.work.State.RUNNING;
import static androidx.work.State.SUCCEEDED;
+import static androidx.work.impl.model.WorkSpec.SCHEDULE_NOT_REQUESTED_YET;
import android.content.Context;
import android.os.Build;
@@ -355,8 +356,17 @@ public class WorkerWrapper implements Runnable {
mWorkSpecDao.setPeriodStartTime(mWorkSpecId, nextPeriodStartTime);
mWorkSpecDao.setState(ENQUEUED, mWorkSpecId);
mWorkSpecDao.resetWorkSpecRunAttemptCount(mWorkSpecId);
- // We need to tell the schedulers that this WorkSpec is no longer occupying a slot.
- mWorkSpecDao.markWorkSpecScheduled(mWorkSpecId, WorkSpec.SCHEDULE_NOT_REQUESTED_YET);
+ if (Build.VERSION.SDK_INT < WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) {
+ // We only need to reset the schedule_requested_at bit for the AlarmManager
+ // implementation because AlarmManager does not know about periodic WorkRequests.
+ // Otherwise we end up double scheduling the Worker with an identical jobId, and
+ // JobScheduler treats it as the first schedule for a PeriodicWorker. With the
+ // AlarmManager implementation, this is not an problem as AlarmManager only cares
+ // about the actual alarm itself.
+
+ // We need to tell the schedulers that this WorkSpec is no longer occupying a slot.
+ mWorkSpecDao.markWorkSpecScheduled(mWorkSpecId, SCHEDULE_NOT_REQUESTED_YET);
+ }
mWorkDatabase.setTransactionSuccessful();
} finally {
mWorkDatabase.endTransaction();
diff --git a/work/workmanager/src/main/java/androidx/work/impl/model/WorkSpec.java b/work/workmanager/src/main/java/androidx/work/impl/model/WorkSpec.java
index 6f5120da5bf..52d30903aea 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/model/WorkSpec.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/model/WorkSpec.java
@@ -114,6 +114,14 @@ public class WorkSpec {
@ColumnInfo(name = "minimum_retention_duration")
public long minimumRetentionDuration;
+ /**
+ * This field tells us if this {@link WorkSpec} instance, is actually currently scheduled and
+ * being counted against the {@code SCHEDULER_LIMIT}. This bit is reset for PeriodicWorkRequests
+ * in API < 23, because AlarmManager does not know of PeriodicWorkRequests. So for the next
+ * request to be rescheduled this field has to be reset to {@code SCHEDULE_NOT_REQUESTED_AT}.
+ * For the JobScheduler implementation, we don't reset this field because JobScheduler natively
+ * supports PeriodicWorkRequests.
+ */
@ColumnInfo(name = "schedule_requested_at")
public long scheduleRequestedAt = SCHEDULE_NOT_REQUESTED_YET;
diff --git a/work/workmanager/src/schemas/androidx.work.impl.WorkDatabase/4.json b/work/workmanager/src/schemas/androidx.work.impl.WorkDatabase/4.json
new file mode 100644
index 00000000000..63c3005deda
--- /dev/null
+++ b/work/workmanager/src/schemas/androidx.work.impl.WorkDatabase/4.json
@@ -0,0 +1,363 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 4,
+ "identityHash": "c45e5fcbdf3824dead9778f19e2fd8af",
+ "entities": [
+ {
+ "tableName": "Dependency",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`work_spec_id` TEXT NOT NULL, `prerequisite_id` TEXT NOT NULL, PRIMARY KEY(`work_spec_id`, `prerequisite_id`), FOREIGN KEY(`work_spec_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`prerequisite_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "workSpecId",
+ "columnName": "work_spec_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "prerequisiteId",
+ "columnName": "prerequisite_id",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "work_spec_id",
+ "prerequisite_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_Dependency_work_spec_id",
+ "unique": false,
+ "columnNames": [
+ "work_spec_id"
+ ],
+ "createSql": "CREATE INDEX `index_Dependency_work_spec_id` ON `${TABLE_NAME}` (`work_spec_id`)"
+ },
+ {
+ "name": "index_Dependency_prerequisite_id",
+ "unique": false,
+ "columnNames": [
+ "prerequisite_id"
+ ],
+ "createSql": "CREATE INDEX `index_Dependency_prerequisite_id` ON `${TABLE_NAME}` (`prerequisite_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "WorkSpec",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "work_spec_id"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ },
+ {
+ "table": "WorkSpec",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "prerequisite_id"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "WorkSpec",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `state` INTEGER NOT NULL, `worker_class_name` TEXT NOT NULL, `input_merger_class_name` TEXT, `input` BLOB NOT NULL, `output` BLOB NOT NULL, `initial_delay` INTEGER NOT NULL, `interval_duration` INTEGER NOT NULL, `flex_duration` INTEGER NOT NULL, `run_attempt_count` INTEGER NOT NULL, `backoff_policy` INTEGER NOT NULL, `backoff_delay_duration` INTEGER NOT NULL, `period_start_time` INTEGER NOT NULL, `minimum_retention_duration` INTEGER NOT NULL, `schedule_requested_at` INTEGER NOT NULL, `required_network_type` INTEGER, `requires_charging` INTEGER NOT NULL, `requires_device_idle` INTEGER NOT NULL, `requires_battery_not_low` INTEGER NOT NULL, `requires_storage_not_low` INTEGER NOT NULL, `content_uri_triggers` BLOB, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "state",
+ "columnName": "state",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "workerClassName",
+ "columnName": "worker_class_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "inputMergerClassName",
+ "columnName": "input_merger_class_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "input",
+ "columnName": "input",
+ "affinity": "BLOB",
+ "notNull": true
+ },
+ {
+ "fieldPath": "output",
+ "columnName": "output",
+ "affinity": "BLOB",
+ "notNull": true
+ },
+ {
+ "fieldPath": "initialDelay",
+ "columnName": "initial_delay",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "intervalDuration",
+ "columnName": "interval_duration",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "flexDuration",
+ "columnName": "flex_duration",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "runAttemptCount",
+ "columnName": "run_attempt_count",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "backoffPolicy",
+ "columnName": "backoff_policy",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "backoffDelayDuration",
+ "columnName": "backoff_delay_duration",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "periodStartTime",
+ "columnName": "period_start_time",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "minimumRetentionDuration",
+ "columnName": "minimum_retention_duration",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "scheduleRequestedAt",
+ "columnName": "schedule_requested_at",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "constraints.mRequiredNetworkType",
+ "columnName": "required_network_type",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "constraints.mRequiresCharging",
+ "columnName": "requires_charging",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "constraints.mRequiresDeviceIdle",
+ "columnName": "requires_device_idle",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "constraints.mRequiresBatteryNotLow",
+ "columnName": "requires_battery_not_low",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "constraints.mRequiresStorageNotLow",
+ "columnName": "requires_storage_not_low",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "constraints.mContentUriTriggers",
+ "columnName": "content_uri_triggers",
+ "affinity": "BLOB",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_WorkSpec_schedule_requested_at",
+ "unique": false,
+ "columnNames": [
+ "schedule_requested_at"
+ ],
+ "createSql": "CREATE INDEX `index_WorkSpec_schedule_requested_at` ON `${TABLE_NAME}` (`schedule_requested_at`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "WorkTag",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag` TEXT NOT NULL, `work_spec_id` TEXT NOT NULL, PRIMARY KEY(`tag`, `work_spec_id`), FOREIGN KEY(`work_spec_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "tag",
+ "columnName": "tag",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "workSpecId",
+ "columnName": "work_spec_id",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "tag",
+ "work_spec_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_WorkTag_work_spec_id",
+ "unique": false,
+ "columnNames": [
+ "work_spec_id"
+ ],
+ "createSql": "CREATE INDEX `index_WorkTag_work_spec_id` ON `${TABLE_NAME}` (`work_spec_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "WorkSpec",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "work_spec_id"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "SystemIdInfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`work_spec_id` TEXT NOT NULL, `system_id` INTEGER NOT NULL, PRIMARY KEY(`work_spec_id`), FOREIGN KEY(`work_spec_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "workSpecId",
+ "columnName": "work_spec_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "systemId",
+ "columnName": "system_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "work_spec_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "WorkSpec",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "work_spec_id"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "WorkName",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `work_spec_id` TEXT NOT NULL, PRIMARY KEY(`name`, `work_spec_id`), FOREIGN KEY(`work_spec_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "workSpecId",
+ "columnName": "work_spec_id",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "name",
+ "work_spec_id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [
+ {
+ "name": "index_WorkName_work_spec_id",
+ "unique": false,
+ "columnNames": [
+ "work_spec_id"
+ ],
+ "createSql": "CREATE INDEX `index_WorkName_work_spec_id` ON `${TABLE_NAME}` (`work_spec_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "WorkSpec",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "work_spec_id"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ }
+ ],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"c45e5fcbdf3824dead9778f19e2fd8af\")"
+ ]
+ }
+} \ No newline at end of file