[GH] Delayed work requests should not be expedited.

Fixes: b/203678406
Test: Added unit tests.

This is an imported pull request from https://github.com/androidx/androidx/pull/257.

Resolves #257
Github-Pr-Head-Sha: 1b78895cb761cc1bb44b26690d90f759d4cbc5f9
GitOrigin-RevId: b192f8999b1d1866f1c29f94f4d277fe86ab62ff
Change-Id: I06924b8f0359f57dd0b84baee6b2d531cfdc9d46
(cherry picked from commit 36d9fe97e1e619f99e59c10b266435d6c826db21)
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/WorkRequestTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/WorkRequestTest.kt
new file mode 100644
index 0000000..4a49ecd
--- /dev/null
+++ b/work/work-runtime/src/androidTest/java/androidx/work/WorkRequestTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.work
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.work.worker.TestWorker
+import org.junit.Assert.assertNotNull
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.concurrent.TimeUnit
+
+@RunWith(AndroidJUnit4::class)
+class WorkRequestTest {
+    @Test
+    @SmallTest
+    public fun expeditedRequest_withInitialDelay_throwsException() {
+        var error: Throwable? = null
+        try {
+            OneTimeWorkRequest.Builder(TestWorker::class.java)
+                .setInitialDelay(10, TimeUnit.SECONDS)
+                .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+                .build()
+        } catch (exception: Throwable) {
+            error = exception
+        }
+        // Delayed work cannot be expedited
+        assertNotNull(error)
+    }
+
+    @Test
+    @SmallTest
+    public fun periodicWorkRequest_expedited_throwsException() {
+        var error: Throwable? = null
+        try {
+            PeriodicWorkRequest.Builder(TestWorker::class.java, 15, TimeUnit.MINUTES)
+                .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+                .build()
+        } catch (exception: Throwable) {
+            error = exception
+        }
+        // Periodic work cannot be expedited
+        assertNotNull(error)
+    }
+}
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobInfoConverterTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobInfoConverterTest.java
index 64a2074..1c2bc79 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobInfoConverterTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobInfoConverterTest.java
@@ -269,6 +269,20 @@
         assertThat(jobInfo.isExpedited(), is(false));
     }
 
+    @Test
+    @SmallTest
+    public void testConvertExpeditedJobs_delaysAreNotExpedited() {
+        if (!BuildCompat.isAtLeastS()) {
+            return;
+        }
+
+        WorkSpec workSpec = new WorkSpec("id", TestWorker.class.getName());
+        workSpec.expedited = true;
+        workSpec.initialDelay = 1000L; // delay
+        JobInfo jobInfo = mConverter.convert(workSpec, JOB_ID);
+        assertThat(jobInfo.isExpedited(), is(false));
+    }
+
     private void convertWithRequiredNetworkType(NetworkType networkType,
                                                 int jobInfoNetworkType,
                                                 int minSdkVersion) {
diff --git a/work/work-runtime/src/main/java/androidx/work/PeriodicWorkRequest.java b/work/work-runtime/src/main/java/androidx/work/PeriodicWorkRequest.java
index fb44604..af5767f 100644
--- a/work/work-runtime/src/main/java/androidx/work/PeriodicWorkRequest.java
+++ b/work/work-runtime/src/main/java/androidx/work/PeriodicWorkRequest.java
@@ -189,6 +189,10 @@
                 throw new IllegalArgumentException(
                         "Cannot set backoff criteria on an idle mode job");
             }
+            if (mWorkSpec.expedited) {
+                throw new IllegalArgumentException(
+                        "PeriodicWorkRequests cannot be expedited");
+            }
             return new PeriodicWorkRequest(this);
         }
 
diff --git a/work/work-runtime/src/main/java/androidx/work/WorkRequest.java b/work/work-runtime/src/main/java/androidx/work/WorkRequest.java
index f54f2f4..678c179 100644
--- a/work/work-runtime/src/main/java/androidx/work/WorkRequest.java
+++ b/work/work-runtime/src/main/java/androidx/work/WorkRequest.java
@@ -317,9 +317,14 @@
                             || constraints.requiresCharging()
                             || (Build.VERSION.SDK_INT >= 23 && constraints.requiresDeviceIdle());
 
-            if (mWorkSpec.expedited && hasUnsupportedConstraints) {
-                throw new IllegalArgumentException(
-                        "Expedited jobs only support network and storage constraints");
+            if (mWorkSpec.expedited) {
+                if (hasUnsupportedConstraints) {
+                    throw new IllegalArgumentException(
+                            "Expedited jobs only support network and storage constraints");
+                }
+                if (mWorkSpec.initialDelay > 0) {
+                    throw new IllegalArgumentException("Expedited jobs cannot be delayed");
+                }
             }
             // Create a new id and WorkSpec so this WorkRequest.Builder can be used multiple times.
             mId = UUID.randomUUID();
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java b/work/work-runtime/src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java
index 02df55e..88fc6af 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/background/systemjob/SystemJobInfoConverter.java
@@ -125,7 +125,8 @@
         }
         // Retries cannot be expedited jobs, given they will occur at some point in the future.
         boolean isRetry = workSpec.runAttemptCount > 0;
-        if (BuildCompat.isAtLeastS() && workSpec.expedited && !isRetry) {
+        boolean isDelayed = offset > 0;
+        if (BuildCompat.isAtLeastS() && workSpec.expedited && !isRetry && !isDelayed) {
             //noinspection NewApi
             builder.setExpedited(true);
         }