diff options
author | Rahul Ravikumar <rahulrav@google.com> | 2018-07-10 10:35:10 -0700 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2018-07-10 10:35:10 -0700 |
commit | e74a0e388018f7d217bd2a6efc73bede96dcd64a (patch) | |
tree | 1fa604cc39cd608146aa60c143ae29d2c1279994 | |
parent | 3a4f96a54a38157aadcafb1be0b179fc2a00bdaa (diff) | |
parent | ca2810524b51260f0bdb7cfde3e8038d9abc6d44 (diff) | |
download | support-pie-qpr1-release.tar.gz |
Merge changes from topic "periodic-work-requests" into pi-preview1-androidx-devandroid-9.0.0_r47android-9.0.0_r46android-9.0.0_r45android-9.0.0_r44android-9.0.0_r43android-9.0.0_r42android-9.0.0_r41android-9.0.0_r40android-9.0.0_r39android-9.0.0_r38android-9.0.0_r37android-9.0.0_r36android-9.0.0_r35android-9.0.0_r34android-9.0.0_r33android-9.0.0_r32android-9.0.0_r31android-9.0.0_r30android-9.0.0_r22android-9.0.0_r21android-9.0.0_r20android-9.0.0_r19android-9.0.0_r16pie-qpr3-s1-releasepie-qpr3-releasepie-qpr3-b-releasepie-qpr2-releasepie-qpr1-s3-releasepie-qpr1-s2-releasepie-qpr1-s1-releasepie-qpr1-releasepie-dr1-devpie-b4s4-releasepie-b4s4-dev
am: ca2810524b
Change-Id: I79ad375291edf687522e48c6502d583ee8a211af
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 |