Add Content Uri Triggers to SystemJobSchedulerConverter
Excluded jobs with Content Uri Triggers from ForegroundProcessor.
Test: Added test to SystemJobInfoConverterTest.
Updated test in WorkManagerTest.
Change-Id: I256bacd53f3d36ca013ef60f7ff4545ed336589c
diff --git a/background/workmanager/src/androidTest/java/android/arch/background/workmanager/WorkManagerTest.java b/background/workmanager/src/androidTest/java/android/arch/background/workmanager/WorkManagerTest.java
index 20b03ed..bd9b7ee 100644
--- a/background/workmanager/src/androidTest/java/android/arch/background/workmanager/WorkManagerTest.java
+++ b/background/workmanager/src/androidTest/java/android/arch/background/workmanager/WorkManagerTest.java
@@ -31,6 +31,7 @@
import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.db.SupportSQLiteOpenHelper;
import android.net.Uri;
+import android.provider.MediaStore;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -129,8 +130,8 @@
@Test
public void testEnqueue_insertWorkConstraints() throws InterruptedException {
- Uri testUri1 = Uri.parse("TEST_URI_1");
- Uri testUri2 = Uri.parse("TEST_URI_2");
+ Uri testUri1 = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ Uri testUri2 = MediaStore.Images.Media.INTERNAL_CONTENT_URI;
Work work0 = new Work.Builder(TestWorker.class)
.withConstraints(
diff --git a/background/workmanager/src/androidTest/java/android/arch/background/workmanager/systemjob/SystemJobInfoConverterTest.java b/background/workmanager/src/androidTest/java/android/arch/background/workmanager/systemjob/SystemJobInfoConverterTest.java
index 6f99143..fccbecf 100644
--- a/background/workmanager/src/androidTest/java/android/arch/background/workmanager/systemjob/SystemJobInfoConverterTest.java
+++ b/background/workmanager/src/androidTest/java/android/arch/background/workmanager/systemjob/SystemJobInfoConverterTest.java
@@ -20,6 +20,7 @@
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.arrayContaining;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -29,6 +30,7 @@
import android.arch.background.workmanager.model.Constraints;
import android.arch.background.workmanager.model.WorkSpec;
import android.arch.background.workmanager.worker.TestWorker;
+import android.net.Uri;
import android.os.Build;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SdkSuppress;
@@ -140,6 +142,21 @@
@Test
@SdkSuppress(minSdkVersion = 24)
+ public void testConvert_requireContentUriTrigger() {
+ final Uri expectedUri = Uri.parse("TEST_URI");
+ final JobInfo.TriggerContentUri expectedTriggerContentUri =
+ new JobInfo.TriggerContentUri(
+ expectedUri, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS);
+ WorkSpec workSpec = getWorkSpec(TestWorker.class, new Constraints.Builder()
+ .addContentUriTrigger(expectedUri, true).build());
+ JobInfo jobInfo = mConverter.convert(workSpec);
+
+ JobInfo.TriggerContentUri[] triggerContentUris = jobInfo.getTriggerContentUris();
+ assertThat(triggerContentUris, is(arrayContaining(expectedTriggerContentUri)));
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 24)
public void testConvert_requireDeviceIdle() {
final boolean expectedRequireDeviceIdle = true;
WorkSpec workSpec = getWorkSpec(TestWorker.class, new Constraints.Builder()
diff --git a/background/workmanager/src/main/java/android/arch/background/workmanager/model/Constraints.java b/background/workmanager/src/main/java/android/arch/background/workmanager/model/Constraints.java
index e876538..b0063d8 100644
--- a/background/workmanager/src/main/java/android/arch/background/workmanager/model/Constraints.java
+++ b/background/workmanager/src/main/java/android/arch/background/workmanager/model/Constraints.java
@@ -132,6 +132,13 @@
return mContentUriTriggers;
}
+ /**
+ * @return {@code true} if {@link ContentUriTriggers} is not empty
+ */
+ public boolean hasContentUriTriggers() {
+ return mContentUriTriggers.size() > 0;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
diff --git a/background/workmanager/src/main/java/android/arch/background/workmanager/model/ContentUriTriggers.java b/background/workmanager/src/main/java/android/arch/background/workmanager/model/ContentUriTriggers.java
index 5afe27f..9553cc2 100644
--- a/background/workmanager/src/main/java/android/arch/background/workmanager/model/ContentUriTriggers.java
+++ b/background/workmanager/src/main/java/android/arch/background/workmanager/model/ContentUriTriggers.java
@@ -30,11 +30,11 @@
import java.util.Set;
/**
- * Stores a set of {@link ContentUriTrigger}s
+ * Stores a set of {@link Trigger}s
*/
-public class ContentUriTriggers implements Iterable<ContentUriTriggers.ContentUriTrigger> {
- private final Set<ContentUriTrigger> mTriggers = new HashSet<>();
+public class ContentUriTriggers implements Iterable<ContentUriTriggers.Trigger> {
+ private final Set<Trigger> mTriggers = new HashSet<>();
/**
* Add a Content {@link Uri} to observe
@@ -43,38 +43,42 @@
* {@link WorkSpec} to run
*/
public void add(Uri uri, boolean triggerForDescendants) {
- ContentUriTrigger trigger = new ContentUriTrigger(uri, triggerForDescendants);
+ Trigger trigger = new Trigger(uri, triggerForDescendants);
mTriggers.add(trigger);
}
@NonNull
@Override
- public Iterator<ContentUriTrigger> iterator() {
+ public Iterator<Trigger> iterator() {
return mTriggers.iterator();
}
/**
- * @return number of {@link ContentUriTrigger} objects
+ * @return number of {@link Trigger} objects
*/
public int size() {
return mTriggers.size();
}
/**
- * Converts a list of {@link ContentUriTrigger}s to byte array representation
- * @param triggers the list of {@link ContentUriTrigger}s to convert
+ * Converts a list of {@link Trigger}s to byte array representation
+ * @param triggers the list of {@link Trigger}s to convert
* @return corresponding byte array representation
*/
@TypeConverter
public static byte[] toByteArray(ContentUriTriggers triggers) {
+ if (triggers.size() == 0) {
+ // Return null for no triggers. Needed for SQL query check in ForegroundProcessor
+ return null;
+ }
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = null;
try {
objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeInt(triggers.size());
- for (ContentUriTrigger trigger : triggers) {
+ for (Trigger trigger : triggers) {
objectOutputStream.writeUTF(trigger.getUri().toString());
- objectOutputStream.writeBoolean(trigger.isTriggerForDescendants());
+ objectOutputStream.writeBoolean(trigger.shouldTriggerForDescendants());
}
} catch (IOException e) {
e.printStackTrace();
@@ -96,13 +100,17 @@
}
/**
- * Converts a byte array to list of {@link ContentUriTrigger}s
+ * Converts a byte array to list of {@link Trigger}s
* @param bytes byte array representation to convert
- * @return list of {@link ContentUriTrigger}s
+ * @return list of {@link Trigger}s
*/
@TypeConverter
public static ContentUriTriggers fromByteArray(byte[] bytes) {
ContentUriTriggers triggers = new ContentUriTriggers();
+ if (bytes == null) {
+ // bytes will be null if there are no Content Uri Triggers
+ return triggers;
+ }
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = null;
try {
@@ -150,13 +158,13 @@
* Defines a content {@link Uri} trigger for a {@link WorkSpec}
*/
- public static class ContentUriTrigger {
+ public static class Trigger {
@NonNull
private final Uri mUri;
private final boolean mTriggerForDescendants;
- public ContentUriTrigger(@NonNull Uri uri,
- boolean triggerForDescendants) {
+ public Trigger(@NonNull Uri uri,
+ boolean triggerForDescendants) {
mUri = uri;
mTriggerForDescendants = triggerForDescendants;
}
@@ -166,7 +174,10 @@
return mUri;
}
- public boolean isTriggerForDescendants() {
+ /**
+ * @return {@code true} if trigger applies to descendants of {@link Uri} also
+ */
+ public boolean shouldTriggerForDescendants() {
return mTriggerForDescendants;
}
@@ -175,7 +186,7 @@
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- ContentUriTrigger trigger = (ContentUriTrigger) o;
+ Trigger trigger = (Trigger) o;
return mTriggerForDescendants == trigger.mTriggerForDescendants
&& mUri.equals(trigger.mUri);
diff --git a/background/workmanager/src/main/java/android/arch/background/workmanager/model/WorkSpecDao.java b/background/workmanager/src/main/java/android/arch/background/workmanager/model/WorkSpecDao.java
index 72e7522..8761e71 100644
--- a/background/workmanager/src/main/java/android/arch/background/workmanager/model/WorkSpecDao.java
+++ b/background/workmanager/src/main/java/android/arch/background/workmanager/model/WorkSpecDao.java
@@ -124,7 +124,8 @@
*/
@Query("SELECT * FROM workspec WHERE status=" + STATUS_ENQUEUED + " AND "
+ " requires_charging=0 AND requires_device_idle=0 AND requires_battery_not_low=0 AND "
- + " requires_storage_not_low=0 AND required_network_type=0 AND interval_duration=0")
+ + " requires_storage_not_low=0 AND required_network_type=0 AND interval_duration=0 AND"
+ + " content_uri_triggers IS NULL")
LiveData<List<WorkSpec>> getForegroundEligibleWorkSpecs();
/**
diff --git a/background/workmanager/src/main/java/android/arch/background/workmanager/systemjob/SystemJobInfoConverter.java b/background/workmanager/src/main/java/android/arch/background/workmanager/systemjob/SystemJobInfoConverter.java
index 037768b..0b5695d 100644
--- a/background/workmanager/src/main/java/android/arch/background/workmanager/systemjob/SystemJobInfoConverter.java
+++ b/background/workmanager/src/main/java/android/arch/background/workmanager/systemjob/SystemJobInfoConverter.java
@@ -21,6 +21,7 @@
import android.app.job.JobInfo;
import android.arch.background.workmanager.Work;
import android.arch.background.workmanager.model.Constraints;
+import android.arch.background.workmanager.model.ContentUriTriggers;
import android.arch.background.workmanager.model.WorkSpec;
import android.content.ComponentName;
import android.content.Context;
@@ -75,7 +76,6 @@
PersistableBundle extras = new PersistableBundle();
extras.putString(EXTRA_WORK_SPEC_ID, workSpec.getId());
JobInfo.Builder builder = new JobInfo.Builder(jobId, mWorkServiceComponent)
- .setPersisted(true)
.setRequiredNetworkType(jobInfoNetworkType)
.setExtras(extras);
@@ -94,6 +94,15 @@
builder.setMinimumLatency(workSpec.getInitialDelay());
}
+ if (Build.VERSION.SDK_INT >= 24 && constraints.hasContentUriTriggers()) {
+ for (ContentUriTriggers.Trigger trigger : constraints.getContentUriTriggers()) {
+ builder.addTriggerContentUri(convertContentUriTrigger(trigger));
+ }
+ } else {
+ // Jobs with Content Uri Triggers cannot be persisted
+ builder.setPersisted(true);
+ }
+
// TODO(janclarin): Support requiresCharging/requiresDeviceIdle for versions older than 24.
if (Build.VERSION.SDK_INT >= 24) {
builder.setRequiresCharging(constraints.requiresCharging());
@@ -108,6 +117,14 @@
return builder.build();
}
+ @RequiresApi(24)
+ private static JobInfo.TriggerContentUri convertContentUriTrigger(
+ ContentUriTriggers.Trigger trigger) {
+ int flag = trigger.shouldTriggerForDescendants()
+ ? JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS : 0;
+ return new JobInfo.TriggerContentUri(trigger.getUri(), flag);
+ }
+
/**
* Converts {@link Constraints.NetworkType} into {@link JobInfo}'s network values.
*