Merge "Special case overrides() check for suspend methods in KAPT." into androidx-main
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
index aca7f19..821fc6c 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
@@ -310,8 +310,6 @@
         setupBlock = {
             if (startupMode == StartupMode.COLD) {
                 killProcess()
-                // drop app pages from page cache to ensure it is loaded from disk, from scratch
-                dropKernelPageCache()
                 // Clear profile caches when possible.
 
                 // Benchmarks get faster over time as ART can create profiles for future
@@ -332,6 +330,15 @@
                         throw IllegalStateException("block never used for CompilationMode.None")
                     }
                 }
+                // drop app pages from page cache to ensure it is loaded from disk, from scratch
+
+                // resetAndCompile uses ProfileInstallReceiver to write a skip file.
+                // This is done to reduce the interference from ProfileInstaller,
+                // so long-running benchmarks don't get optimized due to a background dexopt.
+
+                // To restore the state of the process we need to drop app pages so its
+                // loaded from disk, from scratch.
+                dropKernelPageCache()
             } else if (iteration == 0 && startupMode != null) {
                 try {
                     iteration = null // override to null for warmup, before starting measurements
diff --git a/biometric/biometric/src/test/java/androidx/biometric/BiometricManagerTest.java b/biometric/biometric/src/test/java/androidx/biometric/BiometricManagerTest.java
index 5f22b16..9372b301 100644
--- a/biometric/biometric/src/test/java/androidx/biometric/BiometricManagerTest.java
+++ b/biometric/biometric/src/test/java/androidx/biometric/BiometricManagerTest.java
@@ -65,9 +65,14 @@
     @Config(minSdk = Build.VERSION_CODES.Q)
     @RequiresApi(Build.VERSION_CODES.Q)
     public void testCanAuthenticate_ReturnsSuccess_WhenManagerReturnsSuccess_OnApi29AndAbove() {
+        final int authenticators = Authenticators.BIOMETRIC_WEAK;
         final android.hardware.biometrics.BiometricManager frameworkBiometricManager =
                 mock(android.hardware.biometrics.BiometricManager.class);
         when(frameworkBiometricManager.canAuthenticate()).thenReturn(BIOMETRIC_SUCCESS);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+            when(frameworkBiometricManager.canAuthenticate(authenticators))
+                    .thenReturn(BIOMETRIC_SUCCESS);
+        }
         when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
         when(mFingerprintManager.hasEnrolledFingerprints()).thenReturn(false);
 
@@ -80,17 +85,21 @@
                         .setFingerprintHardwarePresent(true)
                         .build());
 
-        final int authenticators = Authenticators.BIOMETRIC_WEAK;
         assertThat(biometricManager.canAuthenticate(authenticators)).isEqualTo(BIOMETRIC_SUCCESS);
     }
 
     @Test
-    @Config(minSdk = Build.VERSION_CODES.Q, maxSdk = 29)
+    @Config(minSdk = Build.VERSION_CODES.Q)
     @RequiresApi(Build.VERSION_CODES.Q)
     public void testCanAuthenticate_ReturnsError_WhenManagerReturnsNoneEnrolled_OnApi29AndAbove() {
+        final int authenticators = Authenticators.BIOMETRIC_WEAK;
         final android.hardware.biometrics.BiometricManager frameworkBiometricManager =
                 mock(android.hardware.biometrics.BiometricManager.class);
         when(frameworkBiometricManager.canAuthenticate()).thenReturn(BIOMETRIC_ERROR_NONE_ENROLLED);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+            when(frameworkBiometricManager.canAuthenticate(authenticators))
+                    .thenReturn(BIOMETRIC_ERROR_NONE_ENROLLED);
+        }
         when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
         when(mFingerprintManager.hasEnrolledFingerprints()).thenReturn(true);
 
@@ -103,18 +112,22 @@
                         .setFingerprintHardwarePresent(true)
                         .build());
 
-        final int authenticators = Authenticators.BIOMETRIC_WEAK;
         assertThat(biometricManager.canAuthenticate(authenticators))
                 .isEqualTo(BIOMETRIC_ERROR_NONE_ENROLLED);
     }
 
     @Test
-    @Config(minSdk = Build.VERSION_CODES.Q, maxSdk = 29)
+    @Config(minSdk = Build.VERSION_CODES.Q)
     @RequiresApi(Build.VERSION_CODES.Q)
     public void testCanAuthenticate_ReturnsError_WhenManagerReturnsNoHardware_OnApi29AndAbove() {
+        final int authenticators = Authenticators.BIOMETRIC_WEAK;
         final android.hardware.biometrics.BiometricManager frameworkBiometricManager =
                 mock(android.hardware.biometrics.BiometricManager.class);
         when(frameworkBiometricManager.canAuthenticate()).thenReturn(BIOMETRIC_ERROR_NO_HARDWARE);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+            when(frameworkBiometricManager.canAuthenticate(authenticators))
+                    .thenReturn(BIOMETRIC_ERROR_NO_HARDWARE);
+        }
         when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
         when(mFingerprintManager.hasEnrolledFingerprints()).thenReturn(true);
 
@@ -127,7 +140,6 @@
                         .setFingerprintHardwarePresent(true)
                         .build());
 
-        final int authenticators = Authenticators.BIOMETRIC_WEAK;
         assertThat(biometricManager.canAuthenticate(authenticators))
                 .isEqualTo(BIOMETRIC_ERROR_NO_HARDWARE);
     }
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt b/buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt
index f58237b..564b0a8 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt
@@ -19,36 +19,18 @@
 import androidx.build.dependencyTracker.AffectedModuleDetector
 import com.android.build.api.dsl.Lint
 import com.android.build.gradle.internal.lint.AndroidLintAnalysisTask
-import com.android.build.gradle.internal.lint.AndroidLintTextOutputTask
-import com.google.common.io.Files
 import java.io.File
 import java.util.Locale
-import org.gradle.api.DefaultTask
 import org.gradle.api.Project
-import org.gradle.api.file.RegularFileProperty
 import org.gradle.api.services.BuildService
 import org.gradle.api.services.BuildServiceParameters
-import org.gradle.api.tasks.InputFiles
-import org.gradle.api.tasks.OutputFile
-import org.gradle.api.tasks.TaskAction
 import org.gradle.kotlin.dsl.getByType
 
 /**
- * Setting this property means that lint will update lint-baseline.xml if it exists.
- */
-private const val UPDATE_LINT_BASELINE = "updateLintBaseline"
-
-/**
  * Name of the service we use to limit the number of concurrent executions of lint
  */
 public const val LINT_SERVICE_NAME = "androidxLintService"
 
-/**
- * Property used by Lint to continue creating baselines without failing lint, normally set by:
- * -Dlint.baselines.continue=true from command line.
- */
-private const val LINT_BASELINE_CONTINUE = "lint.baselines.continue"
-
 // service for limiting the number of concurrent lint tasks
 interface AndroidXLintService : BuildService<BuildServiceParameters.None>
 
@@ -168,44 +150,16 @@
     // it contains expected violations that we do not want to trigger a build failure
     val isTestingLintItself = (project.path == ":lint-checks:integration-tests")
 
-    // If -PupdateLintBaseline was set we should update the baseline if it exists
-    val updateLintBaseline = project.providers.gradleProperty(UPDATE_LINT_BASELINE).isPresent &&
-        !isTestingLintItself
-
     lint.apply {
         // Skip lintVital tasks on assemble. We explicitly run lintRelease for libraries.
         checkReleaseBuilds = false
     }
 
-    // task to copy autogenerated baselines back into the source tree
-    val replaceLintBaselineTask = project.tasks.register(
-        "replaceLintBaseline",
-        UpdateBaselineTask::class.java,
-    ) { copyTask ->
-        copyTask.source.set(generatedLintBaseline)
-        copyTask.dest.set(lintBaseline)
-    }
-
-    val projectGeneratedLintBaseline = generatedLintBaseline
-
     tasks.withType(AndroidLintAnalysisTask::class.java).configureEach { task ->
         // don't run too many copies of lint at once due to memory limitations
         task.usesService(
             task.project.gradle.sharedServices.registrations.getByName(LINT_SERVICE_NAME).service
         )
-        if (updateLintBaseline) {
-            // Remove the generated baseline before running lint, so that lint won't try to use it
-            task.doFirst {
-                if (projectGeneratedLintBaseline.exists()) {
-                    projectGeneratedLintBaseline.delete()
-                }
-            }
-        }
-    }
-    tasks.withType(AndroidLintTextOutputTask::class.java).configureEach { task ->
-        if (updateLintBaseline) {
-            task.finalizedBy(replaceLintBaselineTask)
-        }
     }
 
     // Lint is configured entirely in finalizeDsl so that individual projects cannot easily
@@ -326,17 +280,6 @@
             lintConfig = File(project.getSupportRootFolder(), lintXmlPath)
         }
 
-        // Ideally, teams aren't able to add new violations to a baseline file; they should only
-        // be able to burn down existing violations. That's hard to enforce, though, so we'll
-        // generally allow teams to update their baseline files with a publicly-known flag.
-        if (updateLintBaseline) {
-            // Continue generating baselines regardless of errors.
-            abortOnError = false
-
-            // Avoid printing every single lint error to the terminal.
-            textReport = false
-        }
-
         val lintBaselineFile = lintBaseline.get().asFile
         // If we give lint the filepath of a baseline file, then:
         //   If the file does not exist, lint will write new violations to it
@@ -347,9 +290,7 @@
 
         // If we're not updating the baselines, then we want lint to check for new errors.
         // This requires us only pass a baseline to lint if one already exists.
-        if (updateLintBaseline) {
-            baseline = generatedLintBaseline
-        } else if (lintBaselineFile.exists()) {
+        if (lintBaselineFile.exists()) {
             baseline = lintBaselineFile
         }
     }
@@ -357,50 +298,3 @@
 
 val Project.lintBaseline get() =
     project.objects.fileProperty().fileValue(File(projectDir, "/lint-baseline.xml"))
-val Project.generatedLintBaseline get() = File(project.buildDir, "/generated-lint-baseline.xml")
-
-/**
- * Task that copies the generated line baseline
- * If an input baseline file has no issues, it is considered to be nonexistent
- */
-abstract class UpdateBaselineTask : DefaultTask() {
-    @get:InputFiles // allows missing input file
-    abstract val source: RegularFileProperty
-
-    @get:OutputFile
-    abstract val dest: RegularFileProperty
-
-    @TaskAction
-    fun copyBaseline() {
-        val source = source.get().asFile
-        val dest = dest.get().asFile
-        val sourceText = if (source.exists()) {
-            source.readText()
-        } else {
-            ""
-        }
-        var sourceHasIssues =
-            if (source.exists()) {
-                // Does the baseline contain any issues?
-                source.reader().useLines { lines ->
-                    lines.any { line ->
-                        line.endsWith("<issue")
-                    }
-                }
-            } else {
-                false
-            }
-        val destNonempty = dest.exists()
-        val changing = (sourceHasIssues != destNonempty) ||
-            (sourceHasIssues && sourceText != dest.readText())
-        if (changing) {
-            if (sourceHasIssues) {
-                Files.copy(source, dest)
-                println("Updated baseline file ${dest.path}")
-            } else {
-                dest.delete()
-                println("Deleted baseline file ${dest.path}")
-            }
-        }
-    }
-}
diff --git a/compose/material/material-window/api/current.txt b/compose/material/material-window/api/current.txt
index c1c9c45..f519e63 100644
--- a/compose/material/material-window/api/current.txt
+++ b/compose/material/material-window/api/current.txt
@@ -9,19 +9,19 @@
   }
 
   public static final class HeightSizeClass.Companion {
-    method public int getCompact();
-    method public int getExpanded();
-    method public int getMedium();
-    property public final int Compact;
-    property public final int Expanded;
-    property public final int Medium;
+    method public String getCompact();
+    method public String getExpanded();
+    method public String getMedium();
+    property public final String Compact;
+    property public final String Expanded;
+    property public final String Medium;
   }
 
   @androidx.compose.runtime.Immutable public final class SizeClass {
-    method public int getHeight();
-    method public int getWidth();
-    property public final int height;
-    property public final int width;
+    method public String getHeight();
+    method public String getWidth();
+    property public final String height;
+    property public final String width;
     field public static final androidx.compose.material.window.SizeClass.Companion Companion;
   }
 
@@ -36,12 +36,12 @@
   }
 
   public static final class WidthSizeClass.Companion {
-    method public int getCompact();
-    method public int getExpanded();
-    method public int getMedium();
-    property public final int Compact;
-    property public final int Expanded;
-    property public final int Medium;
+    method public String getCompact();
+    method public String getExpanded();
+    method public String getMedium();
+    property public final String Compact;
+    property public final String Expanded;
+    property public final String Medium;
   }
 
 }
diff --git a/compose/material/material-window/api/public_plus_experimental_current.txt b/compose/material/material-window/api/public_plus_experimental_current.txt
index 4692a13..a80d3fc 100644
--- a/compose/material/material-window/api/public_plus_experimental_current.txt
+++ b/compose/material/material-window/api/public_plus_experimental_current.txt
@@ -2,9 +2,7 @@
 package androidx.compose.material.window {
 
   public final class AndroidSizeClass_androidKt {
-    method @androidx.compose.material.window.ExperimentalMaterialWindowApi @androidx.compose.runtime.Composable public static int rememberHeightSizeClass(android.app.Activity);
-    method @androidx.compose.material.window.ExperimentalMaterialWindowApi @androidx.compose.runtime.Composable public static androidx.compose.material.window.SizeClass rememberSizeClass(android.app.Activity);
-    method @androidx.compose.material.window.ExperimentalMaterialWindowApi @androidx.compose.runtime.Composable public static int rememberWidthSizeClass(android.app.Activity);
+    method @androidx.compose.material.window.ExperimentalMaterialWindowApi @androidx.compose.runtime.Composable public static androidx.compose.material.window.SizeClass calculateSizeClass(android.app.Activity);
   }
 
   @kotlin.RequiresOptIn(message="This material-window API is experimental and is likely to change or to be removed in" + " the future.") public @interface ExperimentalMaterialWindowApi {
@@ -15,19 +13,19 @@
   }
 
   public static final class HeightSizeClass.Companion {
-    method public int getCompact();
-    method public int getExpanded();
-    method public int getMedium();
-    property public final int Compact;
-    property public final int Expanded;
-    property public final int Medium;
+    method public String getCompact();
+    method public String getExpanded();
+    method public String getMedium();
+    property public final String Compact;
+    property public final String Expanded;
+    property public final String Medium;
   }
 
   @androidx.compose.runtime.Immutable public final class SizeClass {
-    method public int getHeight();
-    method public int getWidth();
-    property public final int height;
-    property public final int width;
+    method public String getHeight();
+    method public String getWidth();
+    property public final String height;
+    property public final String width;
     field public static final androidx.compose.material.window.SizeClass.Companion Companion;
   }
 
@@ -43,12 +41,12 @@
   }
 
   public static final class WidthSizeClass.Companion {
-    method public int getCompact();
-    method public int getExpanded();
-    method public int getMedium();
-    property public final int Compact;
-    property public final int Expanded;
-    property public final int Medium;
+    method public String getCompact();
+    method public String getExpanded();
+    method public String getMedium();
+    property public final String Compact;
+    property public final String Expanded;
+    property public final String Medium;
   }
 
 }
diff --git a/compose/material/material-window/api/restricted_current.txt b/compose/material/material-window/api/restricted_current.txt
index c1c9c45..f519e63 100644
--- a/compose/material/material-window/api/restricted_current.txt
+++ b/compose/material/material-window/api/restricted_current.txt
@@ -9,19 +9,19 @@
   }
 
   public static final class HeightSizeClass.Companion {
-    method public int getCompact();
-    method public int getExpanded();
-    method public int getMedium();
-    property public final int Compact;
-    property public final int Expanded;
-    property public final int Medium;
+    method public String getCompact();
+    method public String getExpanded();
+    method public String getMedium();
+    property public final String Compact;
+    property public final String Expanded;
+    property public final String Medium;
   }
 
   @androidx.compose.runtime.Immutable public final class SizeClass {
-    method public int getHeight();
-    method public int getWidth();
-    property public final int height;
-    property public final int width;
+    method public String getHeight();
+    method public String getWidth();
+    property public final String height;
+    property public final String width;
     field public static final androidx.compose.material.window.SizeClass.Companion Companion;
   }
 
@@ -36,12 +36,12 @@
   }
 
   public static final class WidthSizeClass.Companion {
-    method public int getCompact();
-    method public int getExpanded();
-    method public int getMedium();
-    property public final int Compact;
-    property public final int Expanded;
-    property public final int Medium;
+    method public String getCompact();
+    method public String getExpanded();
+    method public String getMedium();
+    property public final String Compact;
+    property public final String Expanded;
+    property public final String Medium;
   }
 
 }
diff --git a/compose/material/material-window/build.gradle b/compose/material/material-window/build.gradle
index 5700dd6..aeab013 100644
--- a/compose/material/material-window/build.gradle
+++ b/compose/material/material-window/build.gradle
@@ -49,6 +49,8 @@
         androidTestImplementation(libs.testRunner)
         androidTestImplementation(libs.junit)
         androidTestImplementation(libs.truth)
+
+        samples(project(":compose:material:material-window:material-window-samples"))
     }
 }
 
@@ -95,6 +97,9 @@
             }
         }
     }
+    dependencies {
+        samples(project(":compose:material:material-window:material-window-samples"))
+    }
 }
 
 androidx {
diff --git a/compose/material/material-window/samples/build.gradle b/compose/material/material-window/samples/build.gradle
new file mode 100644
index 0000000..4272a48
--- /dev/null
+++ b/compose/material/material-window/samples/build.gradle
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2022 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.
+ */
+
+
+import androidx.build.LibraryType
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("AndroidXComposePlugin")
+    id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+    kotlinPlugin(project(":compose:compiler:compiler"))
+
+    implementation(libs.kotlinStdlib)
+
+    compileOnly(project(":annotation:annotation-sampled"))
+
+    implementation(project(":compose:material:material-window"))
+    implementation(project(":compose:runtime:runtime"))
+    implementation("androidx.activity:activity-compose:1.3.1")
+}
+
+androidx {
+    name = "AndroidX Compose Material Window Samples"
+    type = LibraryType.SAMPLES
+    mavenGroup = LibraryGroups.COMPOSE_MATERIAL
+    inceptionYear = "2022"
+    description = "Contains the sample code for the AndroidX Material Window APIs."
+}
+
+android {
+    namespace "androidx.compose.material.window.samples"
+}
diff --git a/compose/material/material-window/samples/src/main/AndroidManifest.xml b/compose/material/material-window/samples/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a7cd314
--- /dev/null
+++ b/compose/material/material-window/samples/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<!--
+  ~ Copyright (C) 2022 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
+  -->
+
+<manifest />
diff --git a/compose/material/material-window/samples/src/main/java/androidx/compose/material/window/samples/SizeClassSamples.kt b/compose/material/material-window/samples/src/main/java/androidx/compose/material/window/samples/SizeClassSamples.kt
new file mode 100644
index 0000000..5a6b869
--- /dev/null
+++ b/compose/material/material-window/samples/src/main/java/androidx/compose/material/window/samples/SizeClassSamples.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2022 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.compose.material.window.samples
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.annotation.Sampled
+import androidx.compose.material.window.ExperimentalMaterialWindowApi
+import androidx.compose.material.window.WidthSizeClass
+import androidx.compose.material.window.calculateSizeClass
+import androidx.compose.runtime.Composable
+
+@OptIn(ExperimentalMaterialWindowApi::class)
+@Sampled
+fun AndroidSizeClassSample() {
+    class MyActivity : ComponentActivity() {
+        override fun onCreate(savedInstanceState: Bundle?) {
+            super.onCreate(savedInstanceState)
+            setContent {
+                // Calculate the size class for the activity's current window. If the window size
+                // changes, for example when the device is rotated, the value returned by
+                // calculateSizeClass will also change.
+                val sizeClass = calculateSizeClass()
+                // Perform logic on the size class to decide whether to show the top app bar.
+                val showTopAppBar = sizeClass.width != WidthSizeClass.Compact
+
+                // MyScreen knows nothing about window sizes, and performs logic based on a Boolean
+                // flag.
+                MyScreen(showTopAppBar = showTopAppBar)
+            }
+        }
+    }
+}
+
+@Suppress("UNUSED_PARAMETER")
+@Composable
+private fun MyScreen(showTopAppBar: Boolean) {}
diff --git a/compose/material/material-window/src/androidAndroidTest/kotlin/androidx/compose/material/window/AndroidSizeClassTest.kt b/compose/material/material-window/src/androidAndroidTest/kotlin/androidx/compose/material/window/AndroidSizeClassTest.kt
index fe1039b..53a46f1 100644
--- a/compose/material/material-window/src/androidAndroidTest/kotlin/androidx/compose/material/window/AndroidSizeClassTest.kt
+++ b/compose/material/material-window/src/androidAndroidTest/kotlin/androidx/compose/material/window/AndroidSizeClassTest.kt
@@ -43,7 +43,7 @@
     fun widthSizeClass_correctCalculation() {
         var actualWidthSizeClass: WidthSizeClass? = null
         rule.setContent {
-            actualWidthSizeClass = rule.activity.rememberWidthSizeClass()
+            actualWidthSizeClass = rule.activity.calculateSizeClass().width
         }
 
         rule.runOnIdle {
@@ -61,7 +61,7 @@
     fun heightSizeClass_correctCalculation() {
         var actualHeightSizeClass: HeightSizeClass? = null
         rule.setContent {
-            actualHeightSizeClass = rule.activity.rememberHeightSizeClass()
+            actualHeightSizeClass = rule.activity.calculateSizeClass().height
         }
 
         rule.runOnIdle {
@@ -83,7 +83,7 @@
         val density = mutableStateOf(Density(1f))
         rule.setContent {
             CompositionLocalProvider(LocalDensity provides density.value) {
-                actualSizeClass = rule.activity.rememberSizeClass()
+                actualSizeClass = rule.activity.calculateSizeClass()
             }
         }
 
diff --git a/compose/material/material-window/src/androidMain/kotlin/androidx/compose/material/window/AndroidSizeClass.android.kt b/compose/material/material-window/src/androidMain/kotlin/androidx/compose/material/window/AndroidSizeClass.android.kt
index 7695a08..be27854 100644
--- a/compose/material/material-window/src/androidMain/kotlin/androidx/compose/material/window/AndroidSizeClass.android.kt
+++ b/compose/material/material-window/src/androidMain/kotlin/androidx/compose/material/window/AndroidSizeClass.android.kt
@@ -21,50 +21,26 @@
 import androidx.compose.ui.graphics.toComposeRect
 import androidx.compose.ui.platform.LocalConfiguration
 import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.runtime.remember
 import androidx.window.layout.WindowMetricsCalculator
 
 /**
- * Calculates [SizeClass] of the window.
+ * Calculates the window's [SizeClass] for this [Activity].
  *
- * Whenever device configutation changes result in change of the width or height based
- * size classes, for example on device rotation or window resizing, this will return a new
- * [SizeClass] instance.
+ * A new [SizeClass] will be returned whenever a configuration change causes the width or height of
+ * the window to cross a breakpoint, such as when the device is rotated or the window is resized.
+ *
+ * @sample androidx.compose.material.window.samples.AndroidSizeClassSample
  */
 @ExperimentalMaterialWindowApi
 @Composable
-fun Activity.rememberSizeClass(): SizeClass {
-    // observe configuration changes and recalculate size class on corresponding changes
-    val configuration = LocalConfiguration.current
+fun Activity.calculateSizeClass(): SizeClass {
+    // Observe view configuration changes and recalculate the size class on each change. We can't
+    // use Activity#onConfigurationChanged as this will sometimes fail to be called on different
+    // API levels, hence why this function needs to be @Composable so we can observe the
+    // ComposeView's configuration changes.
+    LocalConfiguration.current
     val density = LocalDensity.current
-    return remember(
-        configuration.screenLayout,
-        configuration.screenHeightDp,
-        configuration.screenWidthDp,
-        configuration.orientation,
-        configuration.densityDpi,
-        density.density
-    ) {
-        val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(this)
-        val size = with(density) { metrics.bounds.toComposeRect().size.toDpSize() }
-        SizeClass.calculateFromSize(size)
-    }
+    val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(this)
+    val size = with(density) { metrics.bounds.toComposeRect().size.toDpSize() }
+    return SizeClass.calculateFromSize(size)
 }
-
-/**
- * Calculates [WidthSizeClass] of the window.
- *
- * @see rememberSizeClass
- */
-@ExperimentalMaterialWindowApi
-@Composable
-fun Activity.rememberWidthSizeClass(): WidthSizeClass = rememberSizeClass().width
-
-/**
- * Calculates [HeightSizeClass] of the window.
- *
- * @see rememberSizeClass
- */
-@ExperimentalMaterialWindowApi
-@Composable
-fun Activity.rememberHeightSizeClass(): HeightSizeClass = rememberSizeClass().height
\ No newline at end of file
diff --git a/compose/material/material-window/src/commonMain/kotlin/androidx/compose/material/window/SizeClass.kt b/compose/material/material-window/src/commonMain/kotlin/androidx/compose/material/window/SizeClass.kt
index 44aa060..840fa91 100644
--- a/compose/material/material-window/src/commonMain/kotlin/androidx/compose/material/window/SizeClass.kt
+++ b/compose/material/material-window/src/commonMain/kotlin/androidx/compose/material/window/SizeClass.kt
@@ -22,11 +22,17 @@
 import androidx.compose.ui.unit.dp
 
 /**
- * Window size classes are a set of opinionated viewport breakpoints to design, develop, and test resizable application layouts against.
+ * Window size classes are a set of opinionated viewport breakpoints to design, develop, and test
+ * responsive application layouts against.
  * For more details check <a href="https://developer.android.com/guide/topics/large-screens/support-different-screen-sizes" class="external" target="_blank">Support different screen sizes</a> documentation.
  *
- * @param width width-based size class of the window
- * @param height height-based size class of the window
+ * SizeClass contains a [WidthSizeClass] and [HeightSizeClass], representing the size classes for
+ * this window's width and height respectively.
+ *
+ * See [calculateSizeClass] to calculate the size class for the Activity's current window
+ *
+ * @param width width-based window size class
+ * @param height height-based window size class
  */
 @Immutable
 class SizeClass private constructor(
@@ -35,7 +41,8 @@
 ) {
     companion object {
         /**
-         * Calculates [SizeClass] for a given [size]. Should be used for testing purposes only
+         * Calculates [SizeClass] for a given [size]. Should be used for testing purposes only - to
+         * calculate a [SizeClass] for the Activity's current window see [calculateSizeClass].
          *
          * @param size of the window
          * @return size class corresponding to the given width and height
@@ -71,33 +78,34 @@
 }
 
 /**
- * Width-based size class of the window.
+ * Width-based window size class.
  *
  * A size class represents a breakpoint that can be used to build responsive layouts. Each size
  * class breakpoint represents a majority case for typical device scenarios so your layouts will
  * work well on most devices and configurations.
  *
- * For more details check <a href="https://developer.android.com/guide/topics/large-screens/support-different-screen-sizes#window_size_classes" class="external" target="_blank">Window size classes documentation</a>.
+ * For more details see <a href="https://developer.android.com/guide/topics/large-screens/support-different-screen-sizes#window_size_classes" class="external" target="_blank">Window size classes documentation</a>.
  */
 @Immutable
 @kotlin.jvm.JvmInline
-value class WidthSizeClass private constructor(private val value: Int) {
+value class WidthSizeClass private constructor(private val value: String) {
     companion object {
         /** Represents the majority of phones in portrait. */
-        val Compact = WidthSizeClass(0)
+        val Compact = WidthSizeClass("Compact")
 
         /**
-         * Represents the majority of tablets in portrait and large unfolded inner displays in portrait.
+         * Represents the majority of tablets in portrait and large unfolded inner displays in
+         * portrait.
          */
-        val Medium = WidthSizeClass(1)
+        val Medium = WidthSizeClass("Medium")
 
         /**
          * Represents the majority of tablets in landscape and large unfolded inner displays in
          * landscape.
          */
-        val Expanded = WidthSizeClass(2)
+        val Expanded = WidthSizeClass("Expanded")
 
-        /** Calculates [WidthSizeClass] size class for given [width] */
+        /** Calculates the [WidthSizeClass] for a given [width] */
         internal fun fromWidth(width: Dp): WidthSizeClass {
             require(width >= 0.dp) { "Width must not be negative" }
             return when {
@@ -110,28 +118,28 @@
 }
 
 /**
- * Height-based size class of the window.
+ * Height-based window size class.
  *
  * A size class represents a breakpoint that can be used to build responsive layouts. Each size
  * class breakpoint represents a majority case for typical device scenarios so your layouts will
  * work well on most devices and configurations.
  *
- * For more details check <a href="https://developer.android.com/guide/topics/large-screens/support-different-screen-sizes#window_size_classes" class="external" target="_blank">Window size classes documentation</a>.
+ * For more details see <a href="https://developer.android.com/guide/topics/large-screens/support-different-screen-sizes#window_size_classes" class="external" target="_blank">Window size classes documentation</a>.
  */
 @Immutable
 @kotlin.jvm.JvmInline
-value class HeightSizeClass private constructor(private val value: Int) {
+value class HeightSizeClass private constructor(private val value: String) {
     companion object {
         /** Represents the majority of phones in landscape */
-        val Compact = HeightSizeClass(0)
+        val Compact = HeightSizeClass("Compact")
 
         /** Represents the majority of tablets in landscape and majority of phones in portrait */
-        val Medium = HeightSizeClass(1)
+        val Medium = HeightSizeClass("Medium")
 
         /** Represents the majority of tablets in portrait */
-        val Expanded = HeightSizeClass(2)
+        val Expanded = HeightSizeClass("Expanded")
 
-        /** Calculates [HeightSizeClass] size class for given [height] */
+        /** Calculates the [HeightSizeClass] for a given [height] */
         internal fun fromHeight(height: Dp): HeightSizeClass {
             require(height >= 0.dp) { "Height must not be negative" }
             return when {
@@ -141,4 +149,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/development/update_playground.sh b/development/update_playground.sh
index 8d4c8ba..2df4eac 100755
--- a/development/update_playground.sh
+++ b/development/update_playground.sh
@@ -1,21 +1,29 @@
 #!/bin/bash
 MODE=${1:-s}
+
+# Needed for compat between GNU sed (Linux default) and BSD sed (OSX default).
+#   - GNU sed requires no space between value for -i
+#   - BSD sed requires that a value be passed for -i.
+function fn_sed_inplace {
+  sed -i.bak "$@" && rm "${@: -1}.bak"
+}
+
 function fn_update_snapshot {
   BUILDID_ANDROIDX=`curl -s https://androidx.dev/snapshots/builds | sed -nr 's|.*snapshots/builds/([0-9]*).*|\1|gp' | head -n 1`
   echo "Updating snapshot id: $BUILDID_ANDROIDX"
-  sed -i '' "s/androidx.playground.snapshotBuildId=.*/androidx.playground.snapshotBuildId=$BUILDID_ANDROIDX/g" playground-common/playground.properties
+  fn_sed_inplace "s/androidx.playground.snapshotBuildId=.*/androidx.playground.snapshotBuildId=$BUILDID_ANDROIDX/g" playground-common/playground.properties
 }
 
 function fn_update_metalava {
   BUILDID_METALAVA=`curl -s https://androidx.dev/metalava/builds | sed -nr 's|.*metalava/builds/([0-9]*).*|\1|gp' | head -n 1`
   echo "Updating metalava id: $BUILDID_METALAVA"
-  sed -i '' "s/androidx.playground.metalavaBuildId=.*/androidx.playground.metalavaBuildId=$BUILDID_METALAVA/g" playground-common/playground.properties
+  fn_sed_inplace "s/androidx.playground.metalavaBuildId=.*/androidx.playground.metalavaBuildId=$BUILDID_METALAVA/g" playground-common/playground.properties
 }
 
 function fn_update_dokka {
   BUILDID_DOKKA=`curl -s https://androidx.dev/dokka/builds | sed -nr 's|.*dokka/builds/([0-9]*).*|\1|gp' | head -n 1`
   echo "Updating dokka id: $BUILDID_DOKKA"
-  sed -i '' "s/androidx.playground.dokkaBuildId=.*/androidx.playground.dokkaBuildId=$BUILDID_DOKKA/g" playground-common/playground.properties
+  fn_sed_inplace "s/androidx.playground.dokkaBuildId=.*/androidx.playground.dokkaBuildId=$BUILDID_DOKKA/g" playground-common/playground.properties
 }
 
 if [ "$MODE" == "s" ]; then
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index 925cdf1..023f597 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -64,6 +64,7 @@
     samples(project(":compose:material:material-icons-core:material-icons-core-samples"))
     docs(project(":compose:material:material-ripple"))
     docs(project(":compose:material:material-window"))
+    samples(project(":compose:material:material-window:material-window-samples"))
     samples(project(":compose:material:material:material-samples"))
     docs(project(":compose:runtime:runtime"))
     docs(project(":compose:runtime:runtime-livedata"))
diff --git a/draganddrop/draganddrop/build.gradle b/draganddrop/draganddrop/build.gradle
index 9595f67..5e8aa01 100644
--- a/draganddrop/draganddrop/build.gradle
+++ b/draganddrop/draganddrop/build.gradle
@@ -26,7 +26,6 @@
     api("androidx.appcompat:appcompat:1.4.0")
     api("androidx.core:core:1.7.0")
     annotationProcessor(libs.nullaway)
-    implementation("androidx.core:core:1.3.0-beta01")
     androidTestImplementation(libs.robolectric)
     androidTestImplementation(libs.mockitoAndroid)
 
diff --git a/glance/glance-appwidget/api/current.txt b/glance/glance-appwidget/api/current.txt
index 9ad94e3..4f77155 100644
--- a/glance/glance-appwidget/api/current.txt
+++ b/glance/glance-appwidget/api/current.txt
@@ -101,10 +101,8 @@
 
   public final class ProgressIndicatorDefaults {
     method public androidx.glance.unit.ColorProvider getBackgroundColorProvider();
-    method public long getColor();
     method public androidx.glance.unit.ColorProvider getIndicatorColorProvider();
     property public final androidx.glance.unit.ColorProvider BackgroundColorProvider;
-    property public final long Color;
     property public final androidx.glance.unit.ColorProvider IndicatorColorProvider;
     field public static final androidx.glance.appwidget.ProgressIndicatorDefaults INSTANCE;
   }
diff --git a/glance/glance-appwidget/api/public_plus_experimental_current.txt b/glance/glance-appwidget/api/public_plus_experimental_current.txt
index 89ed7bd..a46cf1d 100644
--- a/glance/glance-appwidget/api/public_plus_experimental_current.txt
+++ b/glance/glance-appwidget/api/public_plus_experimental_current.txt
@@ -109,10 +109,8 @@
 
   public final class ProgressIndicatorDefaults {
     method public androidx.glance.unit.ColorProvider getBackgroundColorProvider();
-    method public long getColor();
     method public androidx.glance.unit.ColorProvider getIndicatorColorProvider();
     property public final androidx.glance.unit.ColorProvider BackgroundColorProvider;
-    property public final long Color;
     property public final androidx.glance.unit.ColorProvider IndicatorColorProvider;
     field public static final androidx.glance.appwidget.ProgressIndicatorDefaults INSTANCE;
   }
diff --git a/glance/glance-appwidget/api/restricted_current.txt b/glance/glance-appwidget/api/restricted_current.txt
index 9ad94e3..4f77155 100644
--- a/glance/glance-appwidget/api/restricted_current.txt
+++ b/glance/glance-appwidget/api/restricted_current.txt
@@ -101,10 +101,8 @@
 
   public final class ProgressIndicatorDefaults {
     method public androidx.glance.unit.ColorProvider getBackgroundColorProvider();
-    method public long getColor();
     method public androidx.glance.unit.ColorProvider getIndicatorColorProvider();
     property public final androidx.glance.unit.ColorProvider BackgroundColorProvider;
-    property public final long Color;
     property public final androidx.glance.unit.ColorProvider IndicatorColorProvider;
     field public static final androidx.glance.appwidget.ProgressIndicatorDefaults INSTANCE;
   }
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/LinearProgressIndicator.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/LinearProgressIndicator.kt
index 216c487..5980189 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/LinearProgressIndicator.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/LinearProgressIndicator.kt
@@ -101,7 +101,7 @@
    * Default color for [LinearProgressIndicator].
    * [Material color specification](https://material.io/design/color/the-color-system.html#color-theme-creation)
    */
-  val Color = Color(0xFF6200EE)
+  private val Color = Color(0xFF6200EE)
 
   /**
    * Default ColorProvider for the progress indicator in [LinearProgressIndicator].
diff --git a/health/health-data-client/api/current.txt b/health/health-data-client/api/current.txt
index fbe2584..7a80848 100644
--- a/health/health-data-client/api/current.txt
+++ b/health/health-data-client/api/current.txt
@@ -176,6 +176,90 @@
     field public static final String STANDING_UP = "standing_up";
   }
 
+  public final class BodyTemperature implements androidx.health.data.client.records.Record {
+    ctor public BodyTemperature(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public String? getMeasurementLocation();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public double getTemperatureDegreesCelsius();
+    method public java.time.Instant getTime();
+    method public java.time.ZoneOffset? getZoneOffset();
+    property public final String? measurementLocation;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public final double temperatureDegreesCelsius;
+    property public java.time.Instant time;
+    property public java.time.ZoneOffset? zoneOffset;
+  }
+
+  public final class BodyTemperatureMeasurementLocations {
+    field public static final String ARMPIT = "armpit";
+    field public static final String EAR = "ear";
+    field public static final String FINGER = "finger";
+    field public static final String FOREHEAD = "forehead";
+    field public static final androidx.health.data.client.records.BodyTemperatureMeasurementLocations INSTANCE;
+    field public static final String MOUTH = "mouth";
+    field public static final String RECTUM = "rectum";
+    field public static final String TEMPORAL_ARTERY = "temporal_artery";
+    field public static final String TOE = "toe";
+    field public static final String VAGINA = "vagina";
+    field public static final String WRIST = "wrist";
+  }
+
+  public final class Distance implements androidx.health.data.client.records.Record {
+    ctor public Distance(double distanceMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public double getDistanceMeters();
+    method public java.time.Instant getEndTime();
+    method public java.time.ZoneOffset? getEndZoneOffset();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getStartTime();
+    method public java.time.ZoneOffset? getStartZoneOffset();
+    property public final double distanceMeters;
+    property public java.time.Instant endTime;
+    property public java.time.ZoneOffset? endZoneOffset;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant startTime;
+    property public java.time.ZoneOffset? startZoneOffset;
+  }
+
+  public final class ElevationGained implements androidx.health.data.client.records.Record {
+    ctor public ElevationGained(double elevationMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public double getElevationMeters();
+    method public java.time.Instant getEndTime();
+    method public java.time.ZoneOffset? getEndZoneOffset();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getStartTime();
+    method public java.time.ZoneOffset? getStartZoneOffset();
+    property public final double elevationMeters;
+    property public java.time.Instant endTime;
+    property public java.time.ZoneOffset? endZoneOffset;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant startTime;
+    property public java.time.ZoneOffset? startZoneOffset;
+  }
+
+  public final class Height implements androidx.health.data.client.records.Record {
+    ctor public Height(double heightMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public double getHeightMeters();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getTime();
+    method public java.time.ZoneOffset? getZoneOffset();
+    property public final double heightMeters;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant time;
+    property public java.time.ZoneOffset? zoneOffset;
+  }
+
+  public final class HipCircumference implements androidx.health.data.client.records.Record {
+    ctor public HipCircumference(double circumferenceMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public double getCircumferenceMeters();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getTime();
+    method public java.time.ZoneOffset? getZoneOffset();
+    property public final double circumferenceMeters;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant time;
+    property public java.time.ZoneOffset? zoneOffset;
+  }
+
   public final class OvulationTestResults {
     field public static final androidx.health.data.client.records.OvulationTestResults INSTANCE;
     field public static final String NEGATIVE = "negative";
diff --git a/health/health-data-client/api/public_plus_experimental_current.txt b/health/health-data-client/api/public_plus_experimental_current.txt
index fbe2584..7a80848 100644
--- a/health/health-data-client/api/public_plus_experimental_current.txt
+++ b/health/health-data-client/api/public_plus_experimental_current.txt
@@ -176,6 +176,90 @@
     field public static final String STANDING_UP = "standing_up";
   }
 
+  public final class BodyTemperature implements androidx.health.data.client.records.Record {
+    ctor public BodyTemperature(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public String? getMeasurementLocation();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public double getTemperatureDegreesCelsius();
+    method public java.time.Instant getTime();
+    method public java.time.ZoneOffset? getZoneOffset();
+    property public final String? measurementLocation;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public final double temperatureDegreesCelsius;
+    property public java.time.Instant time;
+    property public java.time.ZoneOffset? zoneOffset;
+  }
+
+  public final class BodyTemperatureMeasurementLocations {
+    field public static final String ARMPIT = "armpit";
+    field public static final String EAR = "ear";
+    field public static final String FINGER = "finger";
+    field public static final String FOREHEAD = "forehead";
+    field public static final androidx.health.data.client.records.BodyTemperatureMeasurementLocations INSTANCE;
+    field public static final String MOUTH = "mouth";
+    field public static final String RECTUM = "rectum";
+    field public static final String TEMPORAL_ARTERY = "temporal_artery";
+    field public static final String TOE = "toe";
+    field public static final String VAGINA = "vagina";
+    field public static final String WRIST = "wrist";
+  }
+
+  public final class Distance implements androidx.health.data.client.records.Record {
+    ctor public Distance(double distanceMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public double getDistanceMeters();
+    method public java.time.Instant getEndTime();
+    method public java.time.ZoneOffset? getEndZoneOffset();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getStartTime();
+    method public java.time.ZoneOffset? getStartZoneOffset();
+    property public final double distanceMeters;
+    property public java.time.Instant endTime;
+    property public java.time.ZoneOffset? endZoneOffset;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant startTime;
+    property public java.time.ZoneOffset? startZoneOffset;
+  }
+
+  public final class ElevationGained implements androidx.health.data.client.records.Record {
+    ctor public ElevationGained(double elevationMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public double getElevationMeters();
+    method public java.time.Instant getEndTime();
+    method public java.time.ZoneOffset? getEndZoneOffset();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getStartTime();
+    method public java.time.ZoneOffset? getStartZoneOffset();
+    property public final double elevationMeters;
+    property public java.time.Instant endTime;
+    property public java.time.ZoneOffset? endZoneOffset;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant startTime;
+    property public java.time.ZoneOffset? startZoneOffset;
+  }
+
+  public final class Height implements androidx.health.data.client.records.Record {
+    ctor public Height(double heightMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public double getHeightMeters();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getTime();
+    method public java.time.ZoneOffset? getZoneOffset();
+    property public final double heightMeters;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant time;
+    property public java.time.ZoneOffset? zoneOffset;
+  }
+
+  public final class HipCircumference implements androidx.health.data.client.records.Record {
+    ctor public HipCircumference(double circumferenceMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public double getCircumferenceMeters();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getTime();
+    method public java.time.ZoneOffset? getZoneOffset();
+    property public final double circumferenceMeters;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant time;
+    property public java.time.ZoneOffset? zoneOffset;
+  }
+
   public final class OvulationTestResults {
     field public static final androidx.health.data.client.records.OvulationTestResults INSTANCE;
     field public static final String NEGATIVE = "negative";
diff --git a/health/health-data-client/api/restricted_current.txt b/health/health-data-client/api/restricted_current.txt
index fa506c2..af4a3ef 100644
--- a/health/health-data-client/api/restricted_current.txt
+++ b/health/health-data-client/api/restricted_current.txt
@@ -176,6 +176,90 @@
     field public static final String STANDING_UP = "standing_up";
   }
 
+  public final class BodyTemperature implements androidx.health.data.client.records.InstantaneousRecord {
+    ctor public BodyTemperature(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public String? getMeasurementLocation();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public double getTemperatureDegreesCelsius();
+    method public java.time.Instant getTime();
+    method public java.time.ZoneOffset? getZoneOffset();
+    property public final String? measurementLocation;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public final double temperatureDegreesCelsius;
+    property public java.time.Instant time;
+    property public java.time.ZoneOffset? zoneOffset;
+  }
+
+  public final class BodyTemperatureMeasurementLocations {
+    field public static final String ARMPIT = "armpit";
+    field public static final String EAR = "ear";
+    field public static final String FINGER = "finger";
+    field public static final String FOREHEAD = "forehead";
+    field public static final androidx.health.data.client.records.BodyTemperatureMeasurementLocations INSTANCE;
+    field public static final String MOUTH = "mouth";
+    field public static final String RECTUM = "rectum";
+    field public static final String TEMPORAL_ARTERY = "temporal_artery";
+    field public static final String TOE = "toe";
+    field public static final String VAGINA = "vagina";
+    field public static final String WRIST = "wrist";
+  }
+
+  public final class Distance implements androidx.health.data.client.records.IntervalRecord {
+    ctor public Distance(double distanceMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public double getDistanceMeters();
+    method public java.time.Instant getEndTime();
+    method public java.time.ZoneOffset? getEndZoneOffset();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getStartTime();
+    method public java.time.ZoneOffset? getStartZoneOffset();
+    property public final double distanceMeters;
+    property public java.time.Instant endTime;
+    property public java.time.ZoneOffset? endZoneOffset;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant startTime;
+    property public java.time.ZoneOffset? startZoneOffset;
+  }
+
+  public final class ElevationGained implements androidx.health.data.client.records.IntervalRecord {
+    ctor public ElevationGained(double elevationMeters, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public double getElevationMeters();
+    method public java.time.Instant getEndTime();
+    method public java.time.ZoneOffset? getEndZoneOffset();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getStartTime();
+    method public java.time.ZoneOffset? getStartZoneOffset();
+    property public final double elevationMeters;
+    property public java.time.Instant endTime;
+    property public java.time.ZoneOffset? endZoneOffset;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant startTime;
+    property public java.time.ZoneOffset? startZoneOffset;
+  }
+
+  public final class Height implements androidx.health.data.client.records.InstantaneousRecord {
+    ctor public Height(double heightMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public double getHeightMeters();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getTime();
+    method public java.time.ZoneOffset? getZoneOffset();
+    property public final double heightMeters;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant time;
+    property public java.time.ZoneOffset? zoneOffset;
+  }
+
+  public final class HipCircumference implements androidx.health.data.client.records.InstantaneousRecord {
+    ctor public HipCircumference(double circumferenceMeters, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public double getCircumferenceMeters();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getTime();
+    method public java.time.ZoneOffset? getZoneOffset();
+    property public final double circumferenceMeters;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant time;
+    property public java.time.ZoneOffset? zoneOffset;
+  }
+
   @kotlin.PublishedApi internal interface InstantaneousRecord extends androidx.health.data.client.records.Record {
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperature.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperature.kt
index 71825a8..a7dc556 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperature.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperature.kt
@@ -15,7 +15,6 @@
  */
 package androidx.health.data.client.records
 
-import androidx.annotation.RestrictTo
 import androidx.health.data.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
@@ -24,7 +23,6 @@
  * Captures the body temperature of a user. Each record represents a single instantaneous body
  * temperature measurement.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 public class BodyTemperature(
     /** Temperature in degrees Celsius. Required field. Valid range: 0-100. */
     public val temperatureDegreesCelsius: Double,
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperatureMeasurementLocations.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperatureMeasurementLocations.kt
index 84918dd..707ad7f 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperatureMeasurementLocations.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/BodyTemperatureMeasurementLocations.kt
@@ -19,7 +19,6 @@
 import androidx.annotation.StringDef
 
 /** Where on the user's body a temperature measurement was taken from. */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 public object BodyTemperatureMeasurementLocations {
     const val ARMPIT = "armpit"
     const val FINGER = "finger"
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Distance.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/Distance.kt
index 74e40d7..8cbb3ea 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Distance.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/Distance.kt
@@ -15,7 +15,6 @@
  */
 package androidx.health.data.client.records
 
-import androidx.annotation.RestrictTo
 import androidx.health.data.client.aggregate.DoubleAggregateMetric
 import androidx.health.data.client.metadata.Metadata
 import java.time.Instant
@@ -25,9 +24,12 @@
  * Captures distance travelled by the user since the last reading, in meters. The total distance
  * over an interval can be calculated by adding together all the values during the interval. The
  * start time of each record should represent the start of the interval in which the distance was
- * covered. The start time must be equal to or greater than the end time of the previous data point.
+ * covered.
+ *
+ * If break downs are preferred in scenario of a long workout, consider writing multiple distance
+ * records. The start time of each record should be equal to or greater than the end time of the
+ * previous record.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 public class Distance(
     /** Distance in meters. Required field. Valid range: 0-1000000. */
     public val distanceMeters: Double,
@@ -61,10 +63,10 @@
         return result
     }
 
-    companion object {
+    internal companion object {
         /** Metric identifier to retrieve total distance from [AggregateDataRow]. */
         @JvmStatic
-        val DISTANCE_TOTAL: DoubleAggregateMetric =
+        internal val DISTANCE_TOTAL: DoubleAggregateMetric =
             DoubleAggregateMetric("Distance", "total", "distance")
     }
 }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/ElevationGained.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/ElevationGained.kt
index 8ae8530..f5886d14 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/ElevationGained.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/ElevationGained.kt
@@ -15,14 +15,12 @@
  */
 package androidx.health.data.client.records
 
-import androidx.annotation.RestrictTo
 import androidx.health.data.client.aggregate.DoubleAggregateMetric
 import androidx.health.data.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
 /** Captures the elevation gained by the user since the last reading. */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 public class ElevationGained(
     /** Elevation in meters. Required field. Valid range: -1000000-1000000. */
     public val elevationMeters: Double,
@@ -56,10 +54,10 @@
         return result
     }
 
-    companion object {
+    internal companion object {
         /** Metric identifier to retrieve total elevation gained from [AggregateDataRow]. */
         @JvmStatic
-        val ELEVATION_TOTAL: DoubleAggregateMetric =
+        internal val ELEVATION_TOTAL: DoubleAggregateMetric =
             DoubleAggregateMetric("ElevationGained", "total", "elevation")
     }
 }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Height.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/Height.kt
index 471f8b8..8d9b426 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Height.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/Height.kt
@@ -15,14 +15,12 @@
  */
 package androidx.health.data.client.records
 
-import androidx.annotation.RestrictTo
 import androidx.health.data.client.aggregate.DoubleAggregateMetric
 import androidx.health.data.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
 /** Captures the user's height in meters. */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 public class Height(
     /** Height in meters. Required field. Valid range: 0-3. */
     public val heightMeters: Double,
@@ -51,17 +49,20 @@
         return result
     }
 
-    companion object {
+    internal companion object {
         /** Metric identifier to retrieve average height from [AggregateDataRow]. */
         @JvmStatic
-        val HEIGHT_AVG: DoubleAggregateMetric = DoubleAggregateMetric("Height", "avg", "height")
+        internal val HEIGHT_AVG: DoubleAggregateMetric =
+            DoubleAggregateMetric("Height", "avg", "height")
 
         /** Metric identifier to retrieve minimum height from [AggregateDataRow]. */
         @JvmStatic
-        val HEIGHT_MIN: DoubleAggregateMetric = DoubleAggregateMetric("Height", "min", "height")
+        internal val HEIGHT_MIN: DoubleAggregateMetric =
+            DoubleAggregateMetric("Height", "min", "height")
 
         /** Metric identifier to retrieve maximum height from [AggregateDataRow]. */
         @JvmStatic
-        val HEIGHT_MAX: DoubleAggregateMetric = DoubleAggregateMetric("Height", "max", "height")
+        internal val HEIGHT_MAX: DoubleAggregateMetric =
+            DoubleAggregateMetric("Height", "max", "height")
     }
 }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/HipCircumference.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/HipCircumference.kt
index 716a6cd..e82d523 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/HipCircumference.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/HipCircumference.kt
@@ -15,13 +15,11 @@
  */
 package androidx.health.data.client.records
 
-import androidx.annotation.RestrictTo
 import androidx.health.data.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
 /** Captures the user's hip circumference in meters. */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 public class HipCircumference(
     /** Circumference in meters. Required field. Valid range: 0-10. */
     public val circumferenceMeters: Double,
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Pace.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/Pace.kt
deleted file mode 100644
index 5f36e7a..0000000
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Pace.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2022 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.health.data.client.records
-
-import androidx.annotation.RestrictTo
-import androidx.health.data.client.metadata.Metadata
-import java.time.Instant
-import java.time.ZoneOffset
-
-/**
- * Captures the user's pace in minutes per kilometer. The value represents the scalar magnitude of
- * the pace, so negative values should not occur.
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-public class Pace(
-    /** Pace in minutes per kilometer. Required field. Valid range: 0-1000000. */
-    public val pace: Double,
-    override val time: Instant,
-    override val zoneOffset: ZoneOffset?,
-    override val metadata: Metadata = Metadata.EMPTY,
-) : InstantaneousRecord {
-    override fun equals(other: Any?): Boolean {
-        if (this === other) return true
-        if (other !is Pace) return false
-
-        if (pace != other.pace) return false
-        if (time != other.time) return false
-        if (zoneOffset != other.zoneOffset) return false
-        if (metadata != other.metadata) return false
-
-        return true
-    }
-
-    override fun hashCode(): Int {
-        var result = 0
-        result = 31 * result + pace.hashCode()
-        result = 31 * result + time.hashCode()
-        result = 31 * result + (zoneOffset?.hashCode() ?: 0)
-        result = 31 * result + metadata.hashCode()
-        return result
-    }
-}
diff --git a/libraryversions.toml b/libraryversions.toml
index d321fe6..3d28c95 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -38,7 +38,7 @@
 CUSTOMVIEW_POOLINGCONTAINER = "1.0.0-alpha02"
 DATASTORE = "1.1.0-alpha01"
 DOCUMENTFILE = "1.1.0-alpha02"
-DRAGANDDROP = "1.0.0-beta02"
+DRAGANDDROP = "1.0.0-rc01"
 DRAWERLAYOUT = "1.2.0-alpha01"
 DYNAMICANIMATION = "1.1.0-alpha04"
 DYNAMICANIMATION_KTX = "1.0.0-alpha04"
diff --git a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/CustomerViewModel.java b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/CustomerViewModel.java
index 5443931..1fe8c8a 100644
--- a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/CustomerViewModel.java
+++ b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/CustomerViewModel.java
@@ -48,8 +48,10 @@
 
     @SuppressLint("RestrictedApi")
     private void createDb() {
-        mDatabase = Room.databaseBuilder(this.getApplication(),
-                SampleDatabase.class, "customerDatabase").build();
+        mDatabase = Room.databaseBuilder(this.getApplication(), SampleDatabase.class,
+                        "customerDatabase")
+                .fallbackToDestructiveMigration()
+                .build();
 
         ArchTaskExecutor.getInstance().executeOnDiskIO(() -> {
             // fill with some simple data
diff --git a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RemoteKey.kt b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RemoteKey.kt
new file mode 100644
index 0000000..e593fab
--- /dev/null
+++ b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RemoteKey.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2022 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.paging.integration.testapp.room
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+/**
+ * Sample entity to persist remote key for use in RemoteMediator.
+ */
+@Entity(tableName = "remote_key")
+class RemoteKey(val prevKey: Int, val nextKey: Int) {
+    @PrimaryKey
+    var id = 0
+}
diff --git a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RemoteKeyDao.kt b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RemoteKeyDao.kt
new file mode 100644
index 0000000..1b46925
--- /dev/null
+++ b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RemoteKeyDao.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2022 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.paging.integration.testapp.room
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy.Companion.REPLACE
+import androidx.room.Query
+
+/**
+ * Simple Customer DAO for Room Customer list sample.
+ */
+@Dao
+interface RemoteKeyDao {
+    /**
+     * Insert a RemoteKey
+     *
+     * @param remoteKey
+     */
+    @Insert(onConflict = REPLACE)
+    suspend fun insert(remoteKey: RemoteKey)
+
+    /**
+     * Clears the RemoteKey
+     */
+    @Query("DELETE FROM remote_key")
+    fun delete()
+
+    /**
+     * @return Latest persisted RemoteKey
+     */
+    @Query("SELECT * FROM remote_key LIMIT 1")
+    suspend fun queryRemoteKey(): RemoteKey?
+}
diff --git a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/SampleDatabase.java b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/SampleDatabase.java
index 7dac100..1686443 100644
--- a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/SampleDatabase.java
+++ b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/SampleDatabase.java
@@ -16,16 +16,24 @@
 
 package androidx.paging.integration.testapp.room;
 
+import androidx.annotation.NonNull;
 import androidx.room.Database;
 import androidx.room.RoomDatabase;
 
 /**
  * Sample database of customers.
  */
-@Database(entities = {Customer.class}, version = 1, exportSchema = false)
+@Database(entities = {Customer.class, RemoteKey.class}, version = 1, exportSchema = false)
 public abstract class SampleDatabase extends RoomDatabase {
     /**
      * @return customer dao.
      */
+    @NonNull
     public abstract CustomerDao getCustomerDao();
+
+    /**
+     * @return RemoteKeyDao
+     */
+    @NonNull
+    public abstract RemoteKeyDao getRemoteKeyDao();
 }
diff --git a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3room/V3RemoteMediator.kt b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3room/V3RemoteMediator.kt
index fa3204e..490e234 100644
--- a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3room/V3RemoteMediator.kt
+++ b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3room/V3RemoteMediator.kt
@@ -22,6 +22,7 @@
 import androidx.paging.PagingState
 import androidx.paging.RemoteMediator
 import androidx.paging.integration.testapp.room.Customer
+import androidx.paging.integration.testapp.room.RemoteKey
 import androidx.paging.integration.testapp.room.SampleDatabase
 import androidx.room.withTransaction
 import kotlinx.coroutines.Dispatchers
@@ -49,6 +50,13 @@
             return MediatorResult.Success(endOfPaginationReached = true)
         }
 
+        // Fetch latest remote key from db. We cannot rely on PagingState because the
+        // invalidate + load loop in paging may race with the actual load + insert happening in
+        // RemoteMediator.
+        val remoteKey = withContext(Dispatchers.IO) {
+            database.remoteKeyDao.queryRemoteKey() ?: RemoteKey(-1, 0)
+        }
+
         // TODO: Move this to be a more fully featured sample which demonstrated key translation
         //  between two types of PagingSources where the keys do not map 1:1.
         val loadParams = when (loadType) {
@@ -59,7 +67,7 @@
             )
             LoadType.PREPEND -> throw IllegalStateException()
             LoadType.APPEND -> PagingSource.LoadParams.Append(
-                key = state.pages.lastOrNull()?.nextKey ?: 0,
+                key = remoteKey.nextKey,
                 loadSize = 10,
                 placeholdersEnabled = false
             )
@@ -70,9 +78,13 @@
                 withContext(Dispatchers.IO) {
                     database.withTransaction {
                         if (loadType == LoadType.REFRESH) {
+                            database.remoteKeyDao.delete()
                             database.customerDao.removeAll()
                         }
 
+                        database.remoteKeyDao.insert(
+                            RemoteKey(remoteKey.prevKey, remoteKey.nextKey + result.data.size)
+                        )
                         database.customerDao.insertAll(result.data.toTypedArray())
                     }
                 }
diff --git a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3room/V3RoomViewModel.kt b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3room/V3RoomViewModel.kt
index 9a3718d..5c202ee 100644
--- a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3room/V3RoomViewModel.kt
+++ b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3room/V3RoomViewModel.kt
@@ -31,8 +31,8 @@
 import androidx.paging.integration.testapp.room.Customer
 import androidx.paging.integration.testapp.room.SampleDatabase
 import androidx.room.Room
-import kotlinx.coroutines.flow.map
 import java.util.UUID
+import kotlinx.coroutines.flow.map
 
 class V3RoomViewModel(application: Application) : AndroidViewModel(application) {
     val database = Room.databaseBuilder(
@@ -56,8 +56,12 @@
 
     @SuppressLint("RestrictedApi")
     internal fun clearAllCustomers() {
-        ArchTaskExecutor.getInstance()
-            .executeOnDiskIO { database.customerDao.removeAll() }
+        ArchTaskExecutor.getInstance().executeOnDiskIO {
+            database.runInTransaction {
+                database.remoteKeyDao.delete()
+                database.customerDao.removeAll()
+            }
+        }
     }
 
     @OptIn(ExperimentalPagingApi::class)
diff --git a/playground-common/playground.properties b/playground-common/playground.properties
index dcb27a1..1b10ab3 100644
--- a/playground-common/playground.properties
+++ b/playground-common/playground.properties
@@ -25,7 +25,7 @@
 kotlin.code.style=official
 # Disable docs
 androidx.enableDocumentation=false
-androidx.playground.snapshotBuildId=8382462
+androidx.playground.snapshotBuildId=8403616
 androidx.playground.metalavaBuildId=8385786
 androidx.playground.dokkaBuildId=7472101
 androidx.studio.type=playground
diff --git a/room/room-paging/src/main/kotlin/androidx/room/paging/LimitOffsetPagingSource.kt b/room/room-paging/src/main/kotlin/androidx/room/paging/LimitOffsetPagingSource.kt
index 30dab5b..c0a542b 100644
--- a/room/room-paging/src/main/kotlin/androidx/room/paging/LimitOffsetPagingSource.kt
+++ b/room/room-paging/src/main/kotlin/androidx/room/paging/LimitOffsetPagingSource.kt
@@ -21,14 +21,13 @@
 import androidx.annotation.RestrictTo
 import androidx.paging.PagingSource
 import androidx.paging.PagingState
-import androidx.room.InvalidationTracker
 import androidx.room.RoomDatabase
 import androidx.room.RoomSQLiteQuery
 import androidx.room.getQueryDispatcher
+import androidx.room.paging.util.ThreadSafeInvalidationObserver
 import androidx.room.withTransaction
 import androidx.sqlite.db.SupportSQLiteQuery
 import kotlinx.coroutines.withContext
-import java.util.concurrent.atomic.AtomicBoolean
 import java.util.concurrent.atomic.AtomicInteger
 
 /**
@@ -60,16 +59,14 @@
 
     internal val itemCount: AtomicInteger = AtomicInteger(-1)
 
-    private val observer = object : InvalidationTracker.Observer(tables) {
-        override fun onInvalidated(tables: MutableSet<String>) {
-            invalidate()
-        }
-    }
-    private val registeredObserver: AtomicBoolean = AtomicBoolean(false)
+    private val observer = ThreadSafeInvalidationObserver(
+        tables = tables,
+        onInvalidated = ::invalidate
+    )
 
     override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Value> {
         return withContext(db.getQueryDispatcher()) {
-            registerObserverIfNecessary()
+            observer.registerIfNecessary(db)
             val tempCount = itemCount.get()
             // if itemCount is < 0, then it is initial load
             if (tempCount < 0) {
@@ -241,12 +238,6 @@
     @NonNull
     protected abstract fun convertRows(cursor: Cursor): List<Value>
 
-    private fun registerObserverIfNecessary() {
-        if (registeredObserver.compareAndSet(false, true)) {
-            db.invalidationTracker.addWeakObserver(observer)
-        }
-    }
-
     /**
      *  It is unknown whether anchorPosition represents the item at the top of the screen or item at
      *  the bottom of the screen. To ensure the number of items loaded is enough to fill up the
diff --git a/room/room-paging/src/main/kotlin/androidx/room/paging/util/ThreadSafeInvalidationObserver.kt b/room/room-paging/src/main/kotlin/androidx/room/paging/util/ThreadSafeInvalidationObserver.kt
new file mode 100644
index 0000000..90b9fb7
--- /dev/null
+++ b/room/room-paging/src/main/kotlin/androidx/room/paging/util/ThreadSafeInvalidationObserver.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2022 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.room.paging.util
+
+import androidx.annotation.RestrictTo
+import androidx.room.InvalidationTracker
+import androidx.room.RoomDatabase
+import java.util.concurrent.atomic.AtomicBoolean
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class ThreadSafeInvalidationObserver(
+    tables: Array<out String>,
+    val onInvalidated: () -> Unit,
+) : InvalidationTracker.Observer(tables) {
+    private val registered: AtomicBoolean = AtomicBoolean(false)
+
+    override fun onInvalidated(tables: MutableSet<String>) {
+        onInvalidated()
+    }
+
+    fun registerIfNecessary(db: RoomDatabase) {
+        if (registered.compareAndSet(false, true)) {
+            db.invalidationTracker.addWeakObserver(this)
+        }
+    }
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 58d4a8c..19b0107 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -412,6 +412,7 @@
 includeProject(":compose:material:material-icons-extended-twotone", [BuildType.COMPOSE])
 includeProject(":compose:material:material-ripple", [BuildType.COMPOSE])
 includeProject(":compose:material:material-window", [BuildType.COMPOSE])
+includeProject(":compose:material:material-window:material-window-samples", "compose/material/material-window/samples", [BuildType.COMPOSE])
 includeProject(":compose:material:material:icons:generator", [BuildType.COMPOSE])
 includeProject(":compose:material:material:integration-tests:material-demos", [BuildType.COMPOSE])
 includeProject(":compose:material:material:integration-tests:material-catalog", [BuildType.COMPOSE])
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ChipDefaults.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ChipDefaults.java
index 287db2c..192ad83 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ChipDefaults.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ChipDefaults.java
@@ -108,8 +108,8 @@
     public static final DpProp ICON_SIZE = dp(24);
 
     /** The recommended colors for a primary {@link Chip}. */
-    @NonNull public static final ChipColors PRIMARY_COLORS =
-            ChipColors.primaryChipColors(Colors.DEFAULT);
+    @NonNull
+    public static final ChipColors PRIMARY_COLORS = ChipColors.primaryChipColors(Colors.DEFAULT);
 
     /** The recommended colors for a secondary {@link Chip}. */
     @NonNull
diff --git a/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/TimeDifferenceText.java b/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/TimeDifferenceText.java
index 60d5669..84232ff 100644
--- a/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/TimeDifferenceText.java
+++ b/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/TimeDifferenceText.java
@@ -29,6 +29,7 @@
 import java.io.ObjectInputStream;
 import java.io.Serializable;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -71,6 +72,31 @@
         mMinimumUnit = minimumUnit;
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        TimeDifferenceText that = (TimeDifferenceText) o;
+        return mReferencePeriodStart == that.mReferencePeriodStart
+                && mReferencePeriodEnd == that.mReferencePeriodEnd && mStyle == that.mStyle
+                && mShowNowText == that.mShowNowText && mMinimumUnit == that.mMinimumUnit;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mReferencePeriodStart, mReferencePeriodEnd, mStyle, mShowNowText,
+                mMinimumUnit);
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        return "TimeDifferenceText{mReferencePeriodStart=" + mReferencePeriodStart
+                + ", mReferencePeriodEnd=" + mReferencePeriodEnd
+                + ", mStyle=" + mStyle  + ", mShowNowText=" + mShowNowText
+                + ", mMinimumUnit=" + mMinimumUnit + '}';
+    }
+
     private static class SerializedForm implements Serializable {
         long mReferencePeriodStart;
         long mReferencePeriodEnd;
diff --git a/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/TimeFormatText.java b/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/TimeFormatText.java
index e88ced6..43b2c1d 100644
--- a/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/TimeFormatText.java
+++ b/wear/watchface/watchface-complications-data/src/main/java/android/support/wearable/complications/TimeFormatText.java
@@ -28,6 +28,7 @@
 import java.io.Serializable;
 import java.text.SimpleDateFormat;
 import java.util.Date;
+import java.util.Objects;
 import java.util.TimeZone;
 import java.util.concurrent.TimeUnit;
 
@@ -40,6 +41,30 @@
 @RestrictTo(RestrictTo.Scope.LIBRARY)
 public final class TimeFormatText implements TimeDependentText {
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        TimeFormatText that = (TimeFormatText) o;
+        return mStyle == that.mStyle && mTimePrecision == that.mTimePrecision
+                && Objects.equals(mDateFormat, that.mDateFormat) && Objects.equals(
+                mTimeZone, that.mTimeZone)
+                && Objects.equals(mDate.toString(), that.mDate.toString());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mDateFormat, mStyle, mTimeZone, mDate, mTimePrecision);
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        return "TimeFormatText{mDateFormat=" + mDateFormat
+                + ", mStyle=" + mStyle + ", mTimeZone=" + mTimeZone + ", mDate=" + mDate
+                + ", mTimePrecision=" + mTimePrecision + '}';
+    }
+
     private static class DateTimeFormat {
         final String[] mFormatSymbols;
         long mPrecision;
@@ -85,7 +110,7 @@
     }
 
     TimeFormatText(SimpleDateFormat dateFormat,
-            @ComplicationText.TimeFormatStyle  int style,
+            @ComplicationText.TimeFormatStyle int style,
             TimeZone timeZone,
             long timePrecision) {
         mDateFormat = dateFormat;
@@ -97,7 +122,8 @@
 
     private static class SerializedForm implements Serializable {
         SimpleDateFormat mDateFormat;
-        @ComplicationText.TimeFormatStyle int mStyle;
+        @ComplicationText.TimeFormatStyle
+        int mStyle;
         TimeZone mTimeZone;
         long mTimePrecision;
 
diff --git a/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/MainActivity.java b/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/MainActivity.java
index 78f913c..aa83e1c 100644
--- a/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/MainActivity.java
+++ b/work/integration-tests/testapp/src/main/java/androidx/work/integration/testapp/MainActivity.java
@@ -54,6 +54,7 @@
 import androidx.work.WorkRequest;
 import androidx.work.impl.background.systemjob.SystemJobService;
 import androidx.work.impl.workers.ConstraintTrackingWorker;
+import androidx.work.impl.workers.ConstraintTrackingWorkerKt;
 import androidx.work.integration.testapp.imageprocessing.ImageProcessingActivity;
 import androidx.work.integration.testapp.sherlockholmes.AnalyzeSherlockHolmesActivity;
 import androidx.work.multiprocess.RemoteWorkerService;
@@ -376,7 +377,7 @@
                     @Override
                     public void onClick(View v) {
                         Data inputData = new Data.Builder()
-                                .putString(ConstraintTrackingWorker.ARGUMENT_CLASS_NAME,
+                                .putString(ConstraintTrackingWorkerKt.ARGUMENT_CLASS_NAME,
                                         ForegroundWorker.class.getName())
                                 .build();
 
diff --git a/work/work-runtime-ktx/api/api_lint.ignore b/work/work-runtime-ktx/api/api_lint.ignore
index ee82cf9..7a1b7a5 100644
--- a/work/work-runtime-ktx/api/api_lint.ignore
+++ b/work/work-runtime-ktx/api/api_lint.ignore
@@ -1,15 +1,3 @@
 // Baseline format: 1.0
 AsyncSuffixFuture: androidx.work.CoroutineWorker#startWork():
     Methods returning com.google.common.util.concurrent.ListenableFuture should have a suffix *Async to reserve unmodified name for a suspend function
-
-
-MissingNullability: androidx.work.OneTimeWorkRequestKt#OneTimeWorkRequestBuilder():
-    Missing nullability on method `OneTimeWorkRequestBuilder` return
-MissingNullability: androidx.work.PeriodicWorkRequestKt#PeriodicWorkRequestBuilder(java.time.Duration):
-    Missing nullability on method `PeriodicWorkRequestBuilder` return
-MissingNullability: androidx.work.PeriodicWorkRequestKt#PeriodicWorkRequestBuilder(java.time.Duration, java.time.Duration):
-    Missing nullability on method `PeriodicWorkRequestBuilder` return
-MissingNullability: androidx.work.PeriodicWorkRequestKt#PeriodicWorkRequestBuilder(long, java.util.concurrent.TimeUnit):
-    Missing nullability on method `PeriodicWorkRequestBuilder` return
-MissingNullability: androidx.work.PeriodicWorkRequestKt#PeriodicWorkRequestBuilder(long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit):
-    Missing nullability on method `PeriodicWorkRequestBuilder` return
diff --git a/work/work-runtime-ktx/api/current.ignore b/work/work-runtime-ktx/api/current.ignore
index 1c21e58..fb0fcc1 100644
--- a/work/work-runtime-ktx/api/current.ignore
+++ b/work/work-runtime-ktx/api/current.ignore
@@ -1,4 +1,5 @@
 // Baseline format: 1.0
+
 ParameterNameChange: androidx.work.CoroutineWorker#doWork(kotlin.coroutines.Continuation<? super androidx.work.ListenableWorker.Result>) parameter #0:
     Attempted to remove parameter name from parameter arg1 in androidx.work.CoroutineWorker.doWork
 ParameterNameChange: androidx.work.CoroutineWorker#getForegroundInfo(kotlin.coroutines.Continuation<? super androidx.work.ForegroundInfo>) parameter #0:
@@ -9,3 +10,8 @@
     Attempted to remove parameter name from parameter arg2 in androidx.work.CoroutineWorker.setProgress
 ParameterNameChange: androidx.work.OperationKt#await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS>) parameter #1:
     Attempted to remove parameter name from parameter arg2 in androidx.work.OperationKt.await
+
+RemovedClass: androidx.work.OneTimeWorkRequestKt:
+    Removed class androidx.work.OneTimeWorkRequestKt
+RemovedClass: androidx.work.PeriodicWorkRequestKt:
+    Removed class androidx.work.PeriodicWorkRequestKt
diff --git a/work/work-runtime-ktx/api/current.txt b/work/work-runtime-ktx/api/current.txt
index d1cd3d5..efdea4c 100644
--- a/work/work-runtime-ktx/api/current.txt
+++ b/work/work-runtime-ktx/api/current.txt
@@ -22,21 +22,9 @@
   public final class ListenableFutureKt {
   }
 
-  public final class OneTimeWorkRequestKt {
-    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.OneTimeWorkRequest.Builder! OneTimeWorkRequestBuilder();
-    method public static inline androidx.work.OneTimeWorkRequest.Builder setInputMerger(androidx.work.OneTimeWorkRequest.Builder, kotlin.reflect.KClass<? extends androidx.work.InputMerger> inputMerger);
-  }
-
   public final class OperationKt {
     method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS>);
   }
 
-  public final class PeriodicWorkRequestKt {
-    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
-    method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval);
-    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexTimeInterval, java.util.concurrent.TimeUnit flexTimeIntervalUnit);
-    method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval, java.time.Duration flexTimeInterval);
-  }
-
 }
 
diff --git a/work/work-runtime-ktx/api/public_plus_experimental_current.txt b/work/work-runtime-ktx/api/public_plus_experimental_current.txt
index d1cd3d5..efdea4c 100644
--- a/work/work-runtime-ktx/api/public_plus_experimental_current.txt
+++ b/work/work-runtime-ktx/api/public_plus_experimental_current.txt
@@ -22,21 +22,9 @@
   public final class ListenableFutureKt {
   }
 
-  public final class OneTimeWorkRequestKt {
-    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.OneTimeWorkRequest.Builder! OneTimeWorkRequestBuilder();
-    method public static inline androidx.work.OneTimeWorkRequest.Builder setInputMerger(androidx.work.OneTimeWorkRequest.Builder, kotlin.reflect.KClass<? extends androidx.work.InputMerger> inputMerger);
-  }
-
   public final class OperationKt {
     method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS>);
   }
 
-  public final class PeriodicWorkRequestKt {
-    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
-    method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval);
-    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexTimeInterval, java.util.concurrent.TimeUnit flexTimeIntervalUnit);
-    method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval, java.time.Duration flexTimeInterval);
-  }
-
 }
 
diff --git a/work/work-runtime-ktx/api/restricted_current.ignore b/work/work-runtime-ktx/api/restricted_current.ignore
index 1c21e58..fb0fcc1 100644
--- a/work/work-runtime-ktx/api/restricted_current.ignore
+++ b/work/work-runtime-ktx/api/restricted_current.ignore
@@ -1,4 +1,5 @@
 // Baseline format: 1.0
+
 ParameterNameChange: androidx.work.CoroutineWorker#doWork(kotlin.coroutines.Continuation<? super androidx.work.ListenableWorker.Result>) parameter #0:
     Attempted to remove parameter name from parameter arg1 in androidx.work.CoroutineWorker.doWork
 ParameterNameChange: androidx.work.CoroutineWorker#getForegroundInfo(kotlin.coroutines.Continuation<? super androidx.work.ForegroundInfo>) parameter #0:
@@ -9,3 +10,8 @@
     Attempted to remove parameter name from parameter arg2 in androidx.work.CoroutineWorker.setProgress
 ParameterNameChange: androidx.work.OperationKt#await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS>) parameter #1:
     Attempted to remove parameter name from parameter arg2 in androidx.work.OperationKt.await
+
+RemovedClass: androidx.work.OneTimeWorkRequestKt:
+    Removed class androidx.work.OneTimeWorkRequestKt
+RemovedClass: androidx.work.PeriodicWorkRequestKt:
+    Removed class androidx.work.PeriodicWorkRequestKt
diff --git a/work/work-runtime-ktx/api/restricted_current.txt b/work/work-runtime-ktx/api/restricted_current.txt
index d1cd3d5..efdea4c 100644
--- a/work/work-runtime-ktx/api/restricted_current.txt
+++ b/work/work-runtime-ktx/api/restricted_current.txt
@@ -22,21 +22,9 @@
   public final class ListenableFutureKt {
   }
 
-  public final class OneTimeWorkRequestKt {
-    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.OneTimeWorkRequest.Builder! OneTimeWorkRequestBuilder();
-    method public static inline androidx.work.OneTimeWorkRequest.Builder setInputMerger(androidx.work.OneTimeWorkRequest.Builder, kotlin.reflect.KClass<? extends androidx.work.InputMerger> inputMerger);
-  }
-
   public final class OperationKt {
     method public static suspend inline Object? await(androidx.work.Operation, kotlin.coroutines.Continuation<? super androidx.work.Operation.State.SUCCESS>);
   }
 
-  public final class PeriodicWorkRequestKt {
-    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
-    method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval);
-    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexTimeInterval, java.util.concurrent.TimeUnit flexTimeIntervalUnit);
-    method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval, java.time.Duration flexTimeInterval);
-  }
-
 }
 
diff --git a/work/work-runtime-ktx/src/main/java/androidx/work/OneTimeWorkRequest.kt b/work/work-runtime-ktx/src/main/java/androidx/work/OneTimeWorkRequest.kt
deleted file mode 100644
index 60a4d98..0000000
--- a/work/work-runtime-ktx/src/main/java/androidx/work/OneTimeWorkRequest.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-// Always inline ktx extension methods unless we have additional call site costs.
-@file:Suppress("NOTHING_TO_INLINE")
-
-package androidx.work
-
-import androidx.annotation.NonNull
-import kotlin.reflect.KClass
-
-/**
- * Creates a [OneTimeWorkRequest] with the given [ListenableWorker].
- */
-public inline fun <reified W : ListenableWorker> OneTimeWorkRequestBuilder():
-    OneTimeWorkRequest.Builder = OneTimeWorkRequest.Builder(W::class.java)
-
-/**
- * Sets an [InputMerger] on the [OneTimeWorkRequest.Builder].
- */
-public inline fun OneTimeWorkRequest.Builder.setInputMerger(
-    @NonNull inputMerger: KClass<out InputMerger>
-): OneTimeWorkRequest.Builder = setInputMerger(inputMerger.java)
diff --git a/work/work-runtime-ktx/src/main/java/androidx/work/PeriodicWorkRequest.kt b/work/work-runtime-ktx/src/main/java/androidx/work/PeriodicWorkRequest.kt
deleted file mode 100644
index a057043..0000000
--- a/work/work-runtime-ktx/src/main/java/androidx/work/PeriodicWorkRequest.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2018 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.annotation.RequiresApi
-import java.time.Duration
-import java.util.concurrent.TimeUnit
-
-/**
- * Creates a [PeriodicWorkRequest.Builder] with a given [ListenableWorker].
- *
- * @param repeatInterval @see [androidx.work.PeriodicWorkRequest.Builder]
- * @param repeatIntervalTimeUnit @see [androidx.work.PeriodicWorkRequest.Builder]
- */
-public inline fun <reified W : ListenableWorker> PeriodicWorkRequestBuilder(
-    repeatInterval: Long,
-    repeatIntervalTimeUnit: TimeUnit
-): PeriodicWorkRequest.Builder {
-    return PeriodicWorkRequest.Builder(W::class.java, repeatInterval, repeatIntervalTimeUnit)
-}
-
-/**
- * Creates a [PeriodicWorkRequest.Builder] with a given [ListenableWorker].
- *
- * @param repeatInterval @see [androidx.work.PeriodicWorkRequest.Builder]
- */
-@RequiresApi(26)
-public inline fun <reified W : ListenableWorker> PeriodicWorkRequestBuilder(
-    repeatInterval: Duration
-): PeriodicWorkRequest.Builder {
-    return PeriodicWorkRequest.Builder(W::class.java, repeatInterval)
-}
-
-/**
- * Creates a [PeriodicWorkRequest.Builder] with a given [ListenableWorker].
- *
- * @param repeatInterval @see [androidx.work.PeriodicWorkRequest.Builder]
- * @param repeatIntervalTimeUnit @see [androidx.work.PeriodicWorkRequest.Builder]
- * @param flexTimeInterval @see [androidx.work.PeriodicWorkRequest.Builder]
- * @param flexTimeIntervalUnit @see [androidx.work.PeriodicWorkRequest.Builder]
- */
-public inline fun <reified W : ListenableWorker> PeriodicWorkRequestBuilder(
-    repeatInterval: Long,
-    repeatIntervalTimeUnit: TimeUnit,
-    flexTimeInterval: Long,
-    flexTimeIntervalUnit: TimeUnit
-): PeriodicWorkRequest.Builder {
-
-    return PeriodicWorkRequest.Builder(
-        W::class.java,
-        repeatInterval,
-        repeatIntervalTimeUnit,
-        flexTimeInterval,
-        flexTimeIntervalUnit
-    )
-}
-
-/**
- * Creates a [PeriodicWorkRequest.Builder] with a given [ListenableWorker].
- *
- * @param repeatInterval @see [androidx.work.PeriodicWorkRequest.Builder]
- * @param flexTimeInterval @see [androidx.work.PeriodicWorkRequest.Builder]
- */
-@RequiresApi(26)
-public inline fun <reified W : ListenableWorker> PeriodicWorkRequestBuilder(
-    repeatInterval: Duration,
-    flexTimeInterval: Duration
-): PeriodicWorkRequest.Builder {
-    return PeriodicWorkRequest.Builder(W::class.java, repeatInterval, flexTimeInterval)
-}
diff --git a/work/work-runtime/api/api_lint.ignore b/work/work-runtime/api/api_lint.ignore
index 665223c..f3c1cac 100644
--- a/work/work-runtime/api/api_lint.ignore
+++ b/work/work-runtime/api/api_lint.ignore
@@ -126,6 +126,16 @@
 MissingGetterMatchingBuilder: androidx.work.WorkRequest.Builder#setInputData(androidx.work.Data):
     W does not declare a `getInputData()` method matching method androidx.work.WorkRequest.Builder.setInputData(androidx.work.Data)
 
+MissingNullability: androidx.work.OneTimeWorkRequestKt#OneTimeWorkRequestBuilder():
+    Missing nullability on method `OneTimeWorkRequestBuilder` return
+MissingNullability: androidx.work.PeriodicWorkRequestKt#PeriodicWorkRequestBuilder(java.time.Duration):
+    Missing nullability on method `PeriodicWorkRequestBuilder` return
+MissingNullability: androidx.work.PeriodicWorkRequestKt#PeriodicWorkRequestBuilder(java.time.Duration, java.time.Duration):
+    Missing nullability on method `PeriodicWorkRequestBuilder` return
+MissingNullability: androidx.work.PeriodicWorkRequestKt#PeriodicWorkRequestBuilder(long, java.util.concurrent.TimeUnit):
+    Missing nullability on method `PeriodicWorkRequestBuilder` return
+MissingNullability: androidx.work.PeriodicWorkRequestKt#PeriodicWorkRequestBuilder(long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit):
+    Missing nullability on method `PeriodicWorkRequestBuilder` return
 
 NoByteOrShort: androidx.work.Data#getByte(String, byte):
     Should avoid odd sized primitives; use `int` instead of `byte` in method androidx.work.Data.getByte(String,byte)
diff --git a/work/work-runtime/api/current.ignore b/work/work-runtime/api/current.ignore
index d568462..759c5da 100644
--- a/work/work-runtime/api/current.ignore
+++ b/work/work-runtime/api/current.ignore
@@ -1,3 +1,27 @@
 // Baseline format: 1.0
 AddedAbstractMethod: androidx.work.WorkManager#getConfiguration():
     Added method androidx.work.WorkManager.getConfiguration()
+
+
+ChangedType: androidx.work.OneTimeWorkRequest#from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>>):
+    Method androidx.work.OneTimeWorkRequest.from has changed return type from java.util.List<androidx.work.OneTimeWorkRequest!> to java.util.List<androidx.work.OneTimeWorkRequest>
+ChangedType: androidx.work.WorkRequest.Builder#addTag(String):
+    Method androidx.work.WorkRequest.Builder.addTag has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#keepResultsForAtLeast(java.time.Duration):
+    Method androidx.work.WorkRequest.Builder.keepResultsForAtLeast has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#keepResultsForAtLeast(long, java.util.concurrent.TimeUnit):
+    Method androidx.work.WorkRequest.Builder.keepResultsForAtLeast has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration):
+    Method androidx.work.WorkRequest.Builder.setBackoffCriteria has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit):
+    Method androidx.work.WorkRequest.Builder.setBackoffCriteria has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setConstraints(androidx.work.Constraints):
+    Method androidx.work.WorkRequest.Builder.setConstraints has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setExpedited(androidx.work.OutOfQuotaPolicy):
+    Method androidx.work.WorkRequest.Builder.setExpedited has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setInitialDelay(java.time.Duration):
+    Method androidx.work.WorkRequest.Builder.setInitialDelay has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setInitialDelay(long, java.util.concurrent.TimeUnit):
+    Method androidx.work.WorkRequest.Builder.setInitialDelay has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setInputData(androidx.work.Data):
+    Method androidx.work.WorkRequest.Builder.setInputData has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
diff --git a/work/work-runtime/api/current.txt b/work/work-runtime/api/current.txt
index 6df5943..3d3cc10 100644
--- a/work/work-runtime/api/current.txt
+++ b/work/work-runtime/api/current.txt
@@ -208,13 +208,24 @@
   }
 
   public final class OneTimeWorkRequest extends androidx.work.WorkRequest {
-    method public static androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker>);
-    method public static java.util.List<androidx.work.OneTimeWorkRequest!> from(java.util.List<java.lang.Class<? extends androidx.work.ListenableWorker>!>);
+    method public static androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker> workerClass);
+    method public static java.util.List<androidx.work.OneTimeWorkRequest> from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>> workerClasses);
+    field public static final androidx.work.OneTimeWorkRequest.Companion Companion;
   }
 
   public static final class OneTimeWorkRequest.Builder extends androidx.work.WorkRequest.Builder<androidx.work.OneTimeWorkRequest.Builder,androidx.work.OneTimeWorkRequest> {
-    ctor public OneTimeWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>);
-    method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.InputMerger>);
+    ctor public OneTimeWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass);
+    method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.InputMerger> inputMerger);
+  }
+
+  public static final class OneTimeWorkRequest.Companion {
+    method public androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker> workerClass);
+    method public java.util.List<androidx.work.OneTimeWorkRequest> from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>> workerClasses);
+  }
+
+  public final class OneTimeWorkRequestKt {
+    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.OneTimeWorkRequest.Builder! OneTimeWorkRequestBuilder();
+    method public static inline androidx.work.OneTimeWorkRequest.Builder setInputMerger(androidx.work.OneTimeWorkRequest.Builder, kotlin.reflect.KClass<? extends androidx.work.InputMerger> inputMerger);
   }
 
   public interface Operation {
@@ -247,15 +258,26 @@
   }
 
   public final class PeriodicWorkRequest extends androidx.work.WorkRequest {
+    field public static final androidx.work.PeriodicWorkRequest.Companion Companion;
     field public static final long MIN_PERIODIC_FLEX_MILLIS = 300000L; // 0x493e0L
     field public static final long MIN_PERIODIC_INTERVAL_MILLIS = 900000L; // 0xdbba0L
   }
 
   public static final class PeriodicWorkRequest.Builder extends androidx.work.WorkRequest.Builder<androidx.work.PeriodicWorkRequest.Builder,androidx.work.PeriodicWorkRequest> {
-    ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit);
-    ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration);
-    ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit);
-    ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration, java.time.Duration);
+    ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
+    ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, java.time.Duration repeatInterval);
+    ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexInterval, java.util.concurrent.TimeUnit flexIntervalTimeUnit);
+    ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, java.time.Duration repeatInterval, java.time.Duration flexInterval);
+  }
+
+  public static final class PeriodicWorkRequest.Companion {
+  }
+
+  public final class PeriodicWorkRequestKt {
+    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
+    method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval);
+    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexTimeInterval, java.util.concurrent.TimeUnit flexTimeIntervalUnit);
+    method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval, java.time.Duration flexTimeInterval);
   }
 
   public interface ProgressUpdater {
@@ -364,23 +386,28 @@
 
   public abstract class WorkRequest {
     method public java.util.UUID getId();
+    property public java.util.UUID id;
+    field public static final androidx.work.WorkRequest.Companion Companion;
     field public static final long DEFAULT_BACKOFF_DELAY_MILLIS = 30000L; // 0x7530L
     field public static final long MAX_BACKOFF_MILLIS = 18000000L; // 0x112a880L
     field public static final long MIN_BACKOFF_MILLIS = 10000L; // 0x2710L
   }
 
-  public abstract static class WorkRequest.Builder<B extends androidx.work.WorkRequest.Builder<?, ?>, W extends androidx.work.WorkRequest> {
-    method public final B addTag(String);
+  public abstract static class WorkRequest.Builder<B extends androidx.work.WorkRequest.Builder<B, ?>, W extends androidx.work.WorkRequest> {
+    method public final B addTag(String tag);
     method public final W build();
-    method public final B keepResultsForAtLeast(long, java.util.concurrent.TimeUnit);
-    method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration);
-    method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
-    method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
-    method public final B setConstraints(androidx.work.Constraints);
-    method public B setExpedited(androidx.work.OutOfQuotaPolicy);
-    method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
-    method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
-    method public final B setInputData(androidx.work.Data);
+    method public final B keepResultsForAtLeast(long duration, java.util.concurrent.TimeUnit timeUnit);
+    method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration duration);
+    method public final B setBackoffCriteria(androidx.work.BackoffPolicy backoffPolicy, long backoffDelay, java.util.concurrent.TimeUnit timeUnit);
+    method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy backoffPolicy, java.time.Duration duration);
+    method public final B setConstraints(androidx.work.Constraints constraints);
+    method public B setExpedited(androidx.work.OutOfQuotaPolicy policy);
+    method public B setInitialDelay(long duration, java.util.concurrent.TimeUnit timeUnit);
+    method @RequiresApi(26) public B setInitialDelay(java.time.Duration duration);
+    method public final B setInputData(androidx.work.Data inputData);
+  }
+
+  public static final class WorkRequest.Companion {
   }
 
   public abstract class Worker extends androidx.work.ListenableWorker {
diff --git a/work/work-runtime/api/public_plus_experimental_current.txt b/work/work-runtime/api/public_plus_experimental_current.txt
index 6df5943..3d3cc10 100644
--- a/work/work-runtime/api/public_plus_experimental_current.txt
+++ b/work/work-runtime/api/public_plus_experimental_current.txt
@@ -208,13 +208,24 @@
   }
 
   public final class OneTimeWorkRequest extends androidx.work.WorkRequest {
-    method public static androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker>);
-    method public static java.util.List<androidx.work.OneTimeWorkRequest!> from(java.util.List<java.lang.Class<? extends androidx.work.ListenableWorker>!>);
+    method public static androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker> workerClass);
+    method public static java.util.List<androidx.work.OneTimeWorkRequest> from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>> workerClasses);
+    field public static final androidx.work.OneTimeWorkRequest.Companion Companion;
   }
 
   public static final class OneTimeWorkRequest.Builder extends androidx.work.WorkRequest.Builder<androidx.work.OneTimeWorkRequest.Builder,androidx.work.OneTimeWorkRequest> {
-    ctor public OneTimeWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>);
-    method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.InputMerger>);
+    ctor public OneTimeWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass);
+    method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.InputMerger> inputMerger);
+  }
+
+  public static final class OneTimeWorkRequest.Companion {
+    method public androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker> workerClass);
+    method public java.util.List<androidx.work.OneTimeWorkRequest> from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>> workerClasses);
+  }
+
+  public final class OneTimeWorkRequestKt {
+    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.OneTimeWorkRequest.Builder! OneTimeWorkRequestBuilder();
+    method public static inline androidx.work.OneTimeWorkRequest.Builder setInputMerger(androidx.work.OneTimeWorkRequest.Builder, kotlin.reflect.KClass<? extends androidx.work.InputMerger> inputMerger);
   }
 
   public interface Operation {
@@ -247,15 +258,26 @@
   }
 
   public final class PeriodicWorkRequest extends androidx.work.WorkRequest {
+    field public static final androidx.work.PeriodicWorkRequest.Companion Companion;
     field public static final long MIN_PERIODIC_FLEX_MILLIS = 300000L; // 0x493e0L
     field public static final long MIN_PERIODIC_INTERVAL_MILLIS = 900000L; // 0xdbba0L
   }
 
   public static final class PeriodicWorkRequest.Builder extends androidx.work.WorkRequest.Builder<androidx.work.PeriodicWorkRequest.Builder,androidx.work.PeriodicWorkRequest> {
-    ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit);
-    ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration);
-    ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit);
-    ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration, java.time.Duration);
+    ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
+    ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, java.time.Duration repeatInterval);
+    ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexInterval, java.util.concurrent.TimeUnit flexIntervalTimeUnit);
+    ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, java.time.Duration repeatInterval, java.time.Duration flexInterval);
+  }
+
+  public static final class PeriodicWorkRequest.Companion {
+  }
+
+  public final class PeriodicWorkRequestKt {
+    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
+    method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval);
+    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexTimeInterval, java.util.concurrent.TimeUnit flexTimeIntervalUnit);
+    method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval, java.time.Duration flexTimeInterval);
   }
 
   public interface ProgressUpdater {
@@ -364,23 +386,28 @@
 
   public abstract class WorkRequest {
     method public java.util.UUID getId();
+    property public java.util.UUID id;
+    field public static final androidx.work.WorkRequest.Companion Companion;
     field public static final long DEFAULT_BACKOFF_DELAY_MILLIS = 30000L; // 0x7530L
     field public static final long MAX_BACKOFF_MILLIS = 18000000L; // 0x112a880L
     field public static final long MIN_BACKOFF_MILLIS = 10000L; // 0x2710L
   }
 
-  public abstract static class WorkRequest.Builder<B extends androidx.work.WorkRequest.Builder<?, ?>, W extends androidx.work.WorkRequest> {
-    method public final B addTag(String);
+  public abstract static class WorkRequest.Builder<B extends androidx.work.WorkRequest.Builder<B, ?>, W extends androidx.work.WorkRequest> {
+    method public final B addTag(String tag);
     method public final W build();
-    method public final B keepResultsForAtLeast(long, java.util.concurrent.TimeUnit);
-    method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration);
-    method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
-    method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
-    method public final B setConstraints(androidx.work.Constraints);
-    method public B setExpedited(androidx.work.OutOfQuotaPolicy);
-    method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
-    method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
-    method public final B setInputData(androidx.work.Data);
+    method public final B keepResultsForAtLeast(long duration, java.util.concurrent.TimeUnit timeUnit);
+    method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration duration);
+    method public final B setBackoffCriteria(androidx.work.BackoffPolicy backoffPolicy, long backoffDelay, java.util.concurrent.TimeUnit timeUnit);
+    method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy backoffPolicy, java.time.Duration duration);
+    method public final B setConstraints(androidx.work.Constraints constraints);
+    method public B setExpedited(androidx.work.OutOfQuotaPolicy policy);
+    method public B setInitialDelay(long duration, java.util.concurrent.TimeUnit timeUnit);
+    method @RequiresApi(26) public B setInitialDelay(java.time.Duration duration);
+    method public final B setInputData(androidx.work.Data inputData);
+  }
+
+  public static final class WorkRequest.Companion {
   }
 
   public abstract class Worker extends androidx.work.ListenableWorker {
diff --git a/work/work-runtime/api/restricted_current.ignore b/work/work-runtime/api/restricted_current.ignore
index d568462..759c5da 100644
--- a/work/work-runtime/api/restricted_current.ignore
+++ b/work/work-runtime/api/restricted_current.ignore
@@ -1,3 +1,27 @@
 // Baseline format: 1.0
 AddedAbstractMethod: androidx.work.WorkManager#getConfiguration():
     Added method androidx.work.WorkManager.getConfiguration()
+
+
+ChangedType: androidx.work.OneTimeWorkRequest#from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>>):
+    Method androidx.work.OneTimeWorkRequest.from has changed return type from java.util.List<androidx.work.OneTimeWorkRequest!> to java.util.List<androidx.work.OneTimeWorkRequest>
+ChangedType: androidx.work.WorkRequest.Builder#addTag(String):
+    Method androidx.work.WorkRequest.Builder.addTag has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#keepResultsForAtLeast(java.time.Duration):
+    Method androidx.work.WorkRequest.Builder.keepResultsForAtLeast has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#keepResultsForAtLeast(long, java.util.concurrent.TimeUnit):
+    Method androidx.work.WorkRequest.Builder.keepResultsForAtLeast has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration):
+    Method androidx.work.WorkRequest.Builder.setBackoffCriteria has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit):
+    Method androidx.work.WorkRequest.Builder.setBackoffCriteria has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setConstraints(androidx.work.Constraints):
+    Method androidx.work.WorkRequest.Builder.setConstraints has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setExpedited(androidx.work.OutOfQuotaPolicy):
+    Method androidx.work.WorkRequest.Builder.setExpedited has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setInitialDelay(java.time.Duration):
+    Method androidx.work.WorkRequest.Builder.setInitialDelay has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setInitialDelay(long, java.util.concurrent.TimeUnit):
+    Method androidx.work.WorkRequest.Builder.setInitialDelay has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
+ChangedType: androidx.work.WorkRequest.Builder#setInputData(androidx.work.Data):
+    Method androidx.work.WorkRequest.Builder.setInputData has changed return type from B (extends androidx.work.WorkRequest.Builder<?, ?>) to B (extends androidx.work.WorkRequest.Builder<B, ?>)
diff --git a/work/work-runtime/api/restricted_current.txt b/work/work-runtime/api/restricted_current.txt
index 6df5943..3d3cc10 100644
--- a/work/work-runtime/api/restricted_current.txt
+++ b/work/work-runtime/api/restricted_current.txt
@@ -208,13 +208,24 @@
   }
 
   public final class OneTimeWorkRequest extends androidx.work.WorkRequest {
-    method public static androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker>);
-    method public static java.util.List<androidx.work.OneTimeWorkRequest!> from(java.util.List<java.lang.Class<? extends androidx.work.ListenableWorker>!>);
+    method public static androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker> workerClass);
+    method public static java.util.List<androidx.work.OneTimeWorkRequest> from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>> workerClasses);
+    field public static final androidx.work.OneTimeWorkRequest.Companion Companion;
   }
 
   public static final class OneTimeWorkRequest.Builder extends androidx.work.WorkRequest.Builder<androidx.work.OneTimeWorkRequest.Builder,androidx.work.OneTimeWorkRequest> {
-    ctor public OneTimeWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>);
-    method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.InputMerger>);
+    ctor public OneTimeWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass);
+    method public androidx.work.OneTimeWorkRequest.Builder setInputMerger(Class<? extends androidx.work.InputMerger> inputMerger);
+  }
+
+  public static final class OneTimeWorkRequest.Companion {
+    method public androidx.work.OneTimeWorkRequest from(Class<? extends androidx.work.ListenableWorker> workerClass);
+    method public java.util.List<androidx.work.OneTimeWorkRequest> from(java.util.List<? extends java.lang.Class<? extends androidx.work.ListenableWorker>> workerClasses);
+  }
+
+  public final class OneTimeWorkRequestKt {
+    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.OneTimeWorkRequest.Builder! OneTimeWorkRequestBuilder();
+    method public static inline androidx.work.OneTimeWorkRequest.Builder setInputMerger(androidx.work.OneTimeWorkRequest.Builder, kotlin.reflect.KClass<? extends androidx.work.InputMerger> inputMerger);
   }
 
   public interface Operation {
@@ -247,15 +258,26 @@
   }
 
   public final class PeriodicWorkRequest extends androidx.work.WorkRequest {
+    field public static final androidx.work.PeriodicWorkRequest.Companion Companion;
     field public static final long MIN_PERIODIC_FLEX_MILLIS = 300000L; // 0x493e0L
     field public static final long MIN_PERIODIC_INTERVAL_MILLIS = 900000L; // 0xdbba0L
   }
 
   public static final class PeriodicWorkRequest.Builder extends androidx.work.WorkRequest.Builder<androidx.work.PeriodicWorkRequest.Builder,androidx.work.PeriodicWorkRequest> {
-    ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit);
-    ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration);
-    ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit);
-    ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker>, java.time.Duration, java.time.Duration);
+    ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
+    ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, java.time.Duration repeatInterval);
+    ctor public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexInterval, java.util.concurrent.TimeUnit flexIntervalTimeUnit);
+    ctor @RequiresApi(26) public PeriodicWorkRequest.Builder(Class<? extends androidx.work.ListenableWorker> workerClass, java.time.Duration repeatInterval, java.time.Duration flexInterval);
+  }
+
+  public static final class PeriodicWorkRequest.Companion {
+  }
+
+  public final class PeriodicWorkRequestKt {
+    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit);
+    method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval);
+    method public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(long repeatInterval, java.util.concurrent.TimeUnit repeatIntervalTimeUnit, long flexTimeInterval, java.util.concurrent.TimeUnit flexTimeIntervalUnit);
+    method @RequiresApi(26) public static inline <reified W extends androidx.work.ListenableWorker> androidx.work.PeriodicWorkRequest.Builder! PeriodicWorkRequestBuilder(java.time.Duration repeatInterval, java.time.Duration flexTimeInterval);
   }
 
   public interface ProgressUpdater {
@@ -364,23 +386,28 @@
 
   public abstract class WorkRequest {
     method public java.util.UUID getId();
+    property public java.util.UUID id;
+    field public static final androidx.work.WorkRequest.Companion Companion;
     field public static final long DEFAULT_BACKOFF_DELAY_MILLIS = 30000L; // 0x7530L
     field public static final long MAX_BACKOFF_MILLIS = 18000000L; // 0x112a880L
     field public static final long MIN_BACKOFF_MILLIS = 10000L; // 0x2710L
   }
 
-  public abstract static class WorkRequest.Builder<B extends androidx.work.WorkRequest.Builder<?, ?>, W extends androidx.work.WorkRequest> {
-    method public final B addTag(String);
+  public abstract static class WorkRequest.Builder<B extends androidx.work.WorkRequest.Builder<B, ?>, W extends androidx.work.WorkRequest> {
+    method public final B addTag(String tag);
     method public final W build();
-    method public final B keepResultsForAtLeast(long, java.util.concurrent.TimeUnit);
-    method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration);
-    method public final B setBackoffCriteria(androidx.work.BackoffPolicy, long, java.util.concurrent.TimeUnit);
-    method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy, java.time.Duration);
-    method public final B setConstraints(androidx.work.Constraints);
-    method public B setExpedited(androidx.work.OutOfQuotaPolicy);
-    method public B setInitialDelay(long, java.util.concurrent.TimeUnit);
-    method @RequiresApi(26) public B setInitialDelay(java.time.Duration);
-    method public final B setInputData(androidx.work.Data);
+    method public final B keepResultsForAtLeast(long duration, java.util.concurrent.TimeUnit timeUnit);
+    method @RequiresApi(26) public final B keepResultsForAtLeast(java.time.Duration duration);
+    method public final B setBackoffCriteria(androidx.work.BackoffPolicy backoffPolicy, long backoffDelay, java.util.concurrent.TimeUnit timeUnit);
+    method @RequiresApi(26) public final B setBackoffCriteria(androidx.work.BackoffPolicy backoffPolicy, java.time.Duration duration);
+    method public final B setConstraints(androidx.work.Constraints constraints);
+    method public B setExpedited(androidx.work.OutOfQuotaPolicy policy);
+    method public B setInitialDelay(long duration, java.util.concurrent.TimeUnit timeUnit);
+    method @RequiresApi(26) public B setInitialDelay(java.time.Duration duration);
+    method public final B setInputData(androidx.work.Data inputData);
+  }
+
+  public static final class WorkRequest.Companion {
   }
 
   public abstract class Worker extends androidx.work.ListenableWorker {
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
index 2edd07d..52cc8fe 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
@@ -29,6 +29,7 @@
 import static androidx.work.WorkInfo.State.RUNNING;
 import static androidx.work.WorkInfo.State.SUCCEEDED;
 import static androidx.work.impl.model.WorkSpec.SCHEDULE_NOT_REQUESTED_YET;
+import static androidx.work.impl.workers.ConstraintTrackingWorkerKt.ARGUMENT_CLASS_NAME;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
@@ -104,6 +105,7 @@
 import androidx.work.impl.utils.PreferenceUtils;
 import androidx.work.impl.utils.taskexecutor.InstantWorkTaskExecutor;
 import androidx.work.impl.workers.ConstraintTrackingWorker;
+import androidx.work.impl.workers.ConstraintTrackingWorkerKt;
 import androidx.work.worker.InfiniteTestWorker;
 import androidx.work.worker.StopAwareWorker;
 import androidx.work.worker.TestWorker;
@@ -1793,7 +1795,7 @@
         WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(work.getStringId());
         assertThat(workSpec.workerClassName, is(ConstraintTrackingWorker.class.getName()));
         assertThat(workSpec.input.getString(
-                ConstraintTrackingWorker.ARGUMENT_CLASS_NAME),
+                        ConstraintTrackingWorkerKt.ARGUMENT_CLASS_NAME),
                 is(TestWorker.class.getName()));
     }
 
@@ -1811,8 +1813,7 @@
 
         WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(work.getStringId());
         assertThat(workSpec.workerClassName, is(ConstraintTrackingWorker.class.getName()));
-        assertThat(workSpec.input.getString(
-                ConstraintTrackingWorker.ARGUMENT_CLASS_NAME),
+        assertThat(workSpec.input.getString(ARGUMENT_CLASS_NAME),
                 is(TestWorker.class.getName()));
     }
 
@@ -1822,7 +1823,7 @@
     public void testEnqueueApi23To25_withConstraintTrackingWorker_expectsOriginalWorker()
             throws ExecutionException, InterruptedException {
         Data data = new Data.Builder()
-                .put(ConstraintTrackingWorker.ARGUMENT_CLASS_NAME, TestWorker.class.getName())
+                .put(ARGUMENT_CLASS_NAME, TestWorker.class.getName())
                 .build();
 
         OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(ConstraintTrackingWorker.class)
@@ -1835,8 +1836,7 @@
 
         WorkSpec workSpec = mDatabase.workSpecDao().getWorkSpec(work.getStringId());
         assertThat(workSpec.workerClassName, is(ConstraintTrackingWorker.class.getName()));
-        assertThat(workSpec.input.getString(
-                ConstraintTrackingWorker.ARGUMENT_CLASS_NAME),
+        assertThat(workSpec.input.getString(ARGUMENT_CLASS_NAME),
                 is(TestWorker.class.getName()));
     }
 
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java
index d1ed219..eeb8176 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java
@@ -16,6 +16,8 @@
 
 package androidx.work.impl.workers;
 
+import static androidx.work.impl.workers.ConstraintTrackingWorkerKt.ARGUMENT_CLASS_NAME;
+
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -318,7 +320,7 @@
                 .build();
 
         Data input = new Data.Builder()
-                .putString(ConstraintTrackingWorker.ARGUMENT_CLASS_NAME, delegateName)
+                .putString(ARGUMENT_CLASS_NAME, delegateName)
                 .putBoolean(TEST_ARGUMENT_NAME, true)
                 .build();
 
@@ -350,7 +352,6 @@
                 is(CoreMatchers.<ListenableWorker>instanceOf(ConstraintTrackingWorker.class)));
         // mWorker is already a spy
         mWorker = (ConstraintTrackingWorker) worker;
-        when(mWorker.getWorkDatabase()).thenReturn(mDatabase);
     }
 
     private WorkerWrapper.Builder createWorkerWrapperBuilder() {
diff --git a/work/work-runtime/src/main/java/androidx/work/BackoffPolicy.java b/work/work-runtime/src/main/java/androidx/work/BackoffPolicy.java
deleted file mode 100644
index c721565..0000000
--- a/work/work-runtime/src/main/java/androidx/work/BackoffPolicy.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2018 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 java.util.concurrent.TimeUnit;
-
-/**
- * An enumeration of backoff policies when retrying work.  These policies are used when you have a
- * return {@link ListenableWorker.Result#retry()} from a worker to determine the correct backoff
- * time.  Backoff policies are set in
- * {@link WorkRequest.Builder#setBackoffCriteria(BackoffPolicy, long, TimeUnit)} or one of its
- * variants.
- */
-
-public enum BackoffPolicy {
-
-    /**
-     * Used to indicate that {@link WorkManager} should increase the backoff time exponentially
-     */
-    EXPONENTIAL,
-
-    /**
-     * Used to indicate that {@link WorkManager} should increase the backoff time linearly
-     */
-    LINEAR
-}
diff --git a/work/work-runtime/src/main/java/androidx/work/BackoffPolicy.kt b/work/work-runtime/src/main/java/androidx/work/BackoffPolicy.kt
new file mode 100644
index 0000000..e0539b6
--- /dev/null
+++ b/work/work-runtime/src/main/java/androidx/work/BackoffPolicy.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018 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
+
+/**
+ * An enumeration of backoff policies when retrying work.  These policies are used when you have a
+ * return [ListenableWorker.Result.retry] from a worker to determine the correct backoff time.
+ * Backoff policies are set in [WorkRequest.Builder.setBackoffCriteria] or one of its variants.
+ */
+enum class BackoffPolicy {
+    /**
+     * Used to indicate that [WorkManager] should increase the backoff time exponentially
+     */
+    EXPONENTIAL,
+
+    /**
+     * Used to indicate that [WorkManager] should increase the backoff time linearly
+     */
+    LINEAR
+}
\ No newline at end of file
diff --git a/work/work-runtime/src/main/java/androidx/work/ExistingPeriodicWorkPolicy.java b/work/work-runtime/src/main/java/androidx/work/ExistingPeriodicWorkPolicy.kt
similarity index 89%
rename from work/work-runtime/src/main/java/androidx/work/ExistingPeriodicWorkPolicy.java
rename to work/work-runtime/src/main/java/androidx/work/ExistingPeriodicWorkPolicy.kt
index 3fc33f9..d0bc5e3 100644
--- a/work/work-runtime/src/main/java/androidx/work/ExistingPeriodicWorkPolicy.java
+++ b/work/work-runtime/src/main/java/androidx/work/ExistingPeriodicWorkPolicy.kt
@@ -13,16 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package androidx.work;
+package androidx.work
 
 /**
  * An enumeration of the conflict resolution policies available to unique
- * {@link PeriodicWorkRequest}s in case of a collision.
+ * [PeriodicWorkRequest]s in case of a collision.
  */
-
-public enum ExistingPeriodicWorkPolicy {
-
+enum class ExistingPeriodicWorkPolicy {
     /**
      * If there is existing pending (uncompleted) work with the same unique name, cancel and delete
      * it.  Then, insert the newly-specified work.
@@ -34,4 +31,4 @@
      * Otherwise, insert the newly-specified work.
      */
     KEEP
-}
+}
\ No newline at end of file
diff --git a/work/work-runtime/src/main/java/androidx/work/ExistingWorkPolicy.java b/work/work-runtime/src/main/java/androidx/work/ExistingWorkPolicy.kt
similarity index 73%
rename from work/work-runtime/src/main/java/androidx/work/ExistingWorkPolicy.java
rename to work/work-runtime/src/main/java/androidx/work/ExistingWorkPolicy.kt
index 5161c30..455c0d5 100644
--- a/work/work-runtime/src/main/java/androidx/work/ExistingWorkPolicy.java
+++ b/work/work-runtime/src/main/java/androidx/work/ExistingWorkPolicy.kt
@@ -13,19 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package androidx.work;
+package androidx.work
 
 /**
  * An enumeration of the conflict resolution policies available to unique
- * {@link OneTimeWorkRequest}s in case of a collision.
+ * [OneTimeWorkRequest]s in case of a collision.
  */
-
-public enum ExistingWorkPolicy {
-
+enum class ExistingWorkPolicy {
     /**
      * If there is existing pending (uncompleted) work with the same unique name, cancel and delete
-     * it.  Then, insert the newly-specified work.
+     * it. Then, insert the newly-specified work.
      */
     REPLACE,
 
@@ -39,10 +36,10 @@
      * If there is existing pending (uncompleted) work with the same unique name, append the
      * newly-specified work as a child of all the leaves of that work sequence.  Otherwise, insert
      * the newly-specified work as the start of a new sequence.
-     * <br/>
-     * <b>Note:</b> When using APPEND with failed or cancelled prerequisites, newly enqueued work
+     *
+     * **Note:** When using APPEND with failed or cancelled prerequisites, newly enqueued work
      * will also be marked as failed or cancelled respectively. Use
-     * {@link ExistingWorkPolicy#APPEND_OR_REPLACE} to create a new chain of work.
+     * [ExistingWorkPolicy.APPEND_OR_REPLACE] to create a new chain of work.
      */
     APPEND,
 
@@ -50,9 +47,9 @@
      * If there is existing pending (uncompleted) work with the same unique name, append the
      * newly-specified work as the child of all the leaves of that work sequence. Otherwise, insert
      * the newly-specified work as the start of a new sequence.
-     * <br/>
-     * <b>Note:</b> If there are failed or cancelled prerequisites, these prerequisites are
-     * <i>dropped</i> and the newly-specified work is the start of a new sequence.
+     *
+     * **Note:** If there are failed or cancelled prerequisites, these prerequisites are
+     * *dropped* and the newly-specified work is the start of a new sequence.
      */
-    APPEND_OR_REPLACE,
-}
+    APPEND_OR_REPLACE
+}
\ No newline at end of file
diff --git a/work/work-runtime/src/main/java/androidx/work/NetworkType.java b/work/work-runtime/src/main/java/androidx/work/NetworkType.kt
similarity index 83%
rename from work/work-runtime/src/main/java/androidx/work/NetworkType.java
rename to work/work-runtime/src/main/java/androidx/work/NetworkType.kt
index 06d7e3a..ac00245 100644
--- a/work/work-runtime/src/main/java/androidx/work/NetworkType.java
+++ b/work/work-runtime/src/main/java/androidx/work/NetworkType.kt
@@ -13,17 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package androidx.work
 
-package androidx.work;
-
-import androidx.annotation.RequiresApi;
+import androidx.annotation.RequiresApi
 
 /**
- * An enumeration of various network types that can be used as {@link Constraints} for work.
+ * An enumeration of various network types that can be used as [Constraints] for work.
  */
-
-public enum NetworkType {
-
+enum class NetworkType {
     /**
      * A network is not required for this work.
      */
@@ -54,9 +51,9 @@
      * generally metered, but are currently unmetered.
      *
      * Note: This capability can be changed at any time. When it is removed,
-     * {@link ListenableWorker}s are responsible for stopping any data transfer that should not
+     * [ListenableWorker]s are responsible for stopping any data transfer that should not
      * occur on a metered network.
      */
     @RequiresApi(30)
     TEMPORARILY_UNMETERED
-}
+}
\ No newline at end of file
diff --git a/work/work-runtime/src/main/java/androidx/work/OneTimeWorkRequest.java b/work/work-runtime/src/main/java/androidx/work/OneTimeWorkRequest.java
deleted file mode 100644
index d33851e..0000000
--- a/work/work-runtime/src/main/java/androidx/work/OneTimeWorkRequest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 2018 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 android.os.Build;
-
-import androidx.annotation.NonNull;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A {@link WorkRequest} for non-repeating work.
- * <p>
- * OneTimeWorkRequests can be put in simple or complex graphs of work by using methods like
- * {@link WorkManager#beginWith(OneTimeWorkRequest)} or {@link WorkManager#beginWith(List)}.
- */
-
-public final class OneTimeWorkRequest extends WorkRequest {
-
-    /**
-     * Creates a {@link OneTimeWorkRequest} with defaults from a  {@link ListenableWorker} class
-     * name.
-     *
-     * @param workerClass An {@link ListenableWorker} class name
-     * @return A {@link OneTimeWorkRequest} constructed by using defaults in the {@link Builder}
-     */
-    public static @NonNull OneTimeWorkRequest from(
-            @NonNull Class<? extends ListenableWorker> workerClass) {
-        return new OneTimeWorkRequest.Builder(workerClass).build();
-    }
-
-    /**
-     * Creates a list of {@link OneTimeWorkRequest}s with defaults from an array of
-     * {@link ListenableWorker} class names.
-     *
-     * @param workerClasses A list of {@link ListenableWorker} class names
-     * @return A list of {@link OneTimeWorkRequest} constructed by using defaults in the {@link
-     * Builder}
-     */
-    public static @NonNull List<OneTimeWorkRequest> from(
-            @NonNull List<Class<? extends ListenableWorker>> workerClasses) {
-        List<OneTimeWorkRequest> workList = new ArrayList<>(workerClasses.size());
-        for (Class<? extends ListenableWorker> workerClass : workerClasses) {
-            workList.add(new OneTimeWorkRequest.Builder(workerClass).build());
-        }
-        return workList;
-    }
-
-    OneTimeWorkRequest(Builder builder) {
-        super(builder.mId, builder.mWorkSpec, builder.mTags);
-    }
-
-    /**
-     * Builder for {@link OneTimeWorkRequest}s.
-     */
-    public static final class Builder extends WorkRequest.Builder<Builder, OneTimeWorkRequest> {
-
-        /**
-         * Creates a {@link OneTimeWorkRequest}.
-         *
-         * @param workerClass The {@link ListenableWorker} class to run for this work
-         */
-        public Builder(@NonNull Class<? extends ListenableWorker> workerClass) {
-            super(workerClass);
-            mWorkSpec.inputMergerClassName = OverwritingInputMerger.class.getName();
-        }
-
-        /**
-         * Specifies the {@link InputMerger} class name for this {@link OneTimeWorkRequest}.
-         * <p>
-         * Before workers run, they receive input {@link Data} from their parent workers, as well as
-         * anything specified directly to them via {@link WorkRequest.Builder#setInputData(Data)}.
-         * An InputMerger takes all of these objects and converts them to a single merged
-         * {@link Data} to be used as the worker input.  The default InputMerger is
-         * {@link OverwritingInputMerger}.  This library also offers
-         * {@link ArrayCreatingInputMerger}; you can also specify your own.
-         *
-         * @param inputMerger The class name of the {@link InputMerger} for this
-         *                    {@link OneTimeWorkRequest}
-         * @return The current {@link Builder}
-         */
-        public @NonNull Builder setInputMerger(@NonNull Class<? extends InputMerger> inputMerger) {
-            mWorkSpec.inputMergerClassName = inputMerger.getName();
-            return this;
-        }
-
-        @Override
-        @NonNull OneTimeWorkRequest buildInternal() {
-            if (mBackoffCriteriaSet
-                    && Build.VERSION.SDK_INT >= 23
-                    && mWorkSpec.constraints.requiresDeviceIdle()) {
-                throw new IllegalArgumentException(
-                        "Cannot set backoff criteria on an idle mode job");
-            }
-            return new OneTimeWorkRequest(this);
-        }
-
-        @Override
-        @NonNull Builder getThis() {
-            return this;
-        }
-    }
-}
diff --git a/work/work-runtime/src/main/java/androidx/work/OneTimeWorkRequest.kt b/work/work-runtime/src/main/java/androidx/work/OneTimeWorkRequest.kt
new file mode 100644
index 0000000..f8f696a
--- /dev/null
+++ b/work/work-runtime/src/main/java/androidx/work/OneTimeWorkRequest.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2018 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 android.os.Build
+import androidx.annotation.NonNull
+import kotlin.reflect.KClass
+
+/**
+ * A [WorkRequest] for non-repeating work.
+ *
+ * OneTimeWorkRequests can be put in simple or complex graphs of work by using methods like
+ * [WorkManager.beginWith] or [WorkManager.beginWith].
+ */
+class OneTimeWorkRequest internal constructor(builder: Builder) :
+    WorkRequest(builder.id, builder.workSpec, builder.tags) {
+    /**
+     * Builder for [OneTimeWorkRequest]s.
+     *
+     * @param workerClass The [ListenableWorker] class to run for this work
+     */
+    class Builder(workerClass: Class<out ListenableWorker>) :
+        WorkRequest.Builder<Builder, OneTimeWorkRequest>(workerClass) {
+
+        init {
+            workSpec.inputMergerClassName = OverwritingInputMerger::class.java.name
+        }
+
+        /**
+         * Specifies the [InputMerger] class name for this [OneTimeWorkRequest].
+         *
+         * Before workers run, they receive input [Data] from their parent workers, as well as
+         * anything specified directly to them via [WorkRequest.Builder.setInputData].
+         * An InputMerger takes all of these objects and converts them to a single merged
+         * [Data] to be used as the worker input.  The default InputMerger is
+         * [OverwritingInputMerger].  This library also offers
+         * [ArrayCreatingInputMerger]; you can also specify your own.
+         *
+         * @param inputMerger The class name of the [InputMerger] for this
+         * [OneTimeWorkRequest]
+         * @return The current [Builder]
+         */
+        fun setInputMerger(inputMerger: Class<out InputMerger>): Builder {
+            workSpec.inputMergerClassName = inputMerger.name
+            return this
+        }
+
+        override fun buildInternal(): OneTimeWorkRequest {
+            require(
+                !(backoffCriteriaSet && Build.VERSION.SDK_INT >= 23 &&
+                    workSpec.constraints.requiresDeviceIdle())
+            ) { "Cannot set backoff criteria on an idle mode job" }
+            return OneTimeWorkRequest(this)
+        }
+
+        override val thisObject: Builder
+            get() = this
+    }
+
+    companion object {
+        /**
+         * Creates a [OneTimeWorkRequest] with defaults from a  [ListenableWorker] class
+         * name.
+         *
+         * @param workerClass An [ListenableWorker] class name
+         * @return A [OneTimeWorkRequest] constructed by using defaults in the [Builder]
+         */
+        @JvmStatic
+        fun from(workerClass: Class<out ListenableWorker>): OneTimeWorkRequest {
+            return Builder(workerClass).build()
+        }
+
+        /**
+         * Creates a list of [OneTimeWorkRequest]s with defaults from an array of
+         * [ListenableWorker] class names.
+         *
+         * @param workerClasses A list of [ListenableWorker] class names
+         * @return A list of [OneTimeWorkRequest] constructed by using defaults in the [ ]
+         */
+        @JvmStatic
+        fun from(workerClasses: List<Class<out ListenableWorker>>): List<OneTimeWorkRequest> {
+            return workerClasses.map { Builder(it).build() }
+        }
+    }
+}
+
+/**
+ * Creates a [OneTimeWorkRequest] with the given [ListenableWorker].
+ */
+public inline fun <reified W : ListenableWorker> OneTimeWorkRequestBuilder():
+    OneTimeWorkRequest.Builder = OneTimeWorkRequest.Builder(W::class.java)
+
+/**
+ * Sets an [InputMerger] on the [OneTimeWorkRequest.Builder].
+ */
+@Suppress("NOTHING_TO_INLINE")
+public inline fun OneTimeWorkRequest.Builder.setInputMerger(
+    @NonNull inputMerger: KClass<out InputMerger>
+): OneTimeWorkRequest.Builder = setInputMerger(inputMerger.java)
diff --git a/work/work-runtime/src/main/java/androidx/work/OutOfQuotaPolicy.java b/work/work-runtime/src/main/java/androidx/work/OutOfQuotaPolicy.kt
similarity index 92%
rename from work/work-runtime/src/main/java/androidx/work/OutOfQuotaPolicy.java
rename to work/work-runtime/src/main/java/androidx/work/OutOfQuotaPolicy.kt
index aaa7b25..0d8747a 100644
--- a/work/work-runtime/src/main/java/androidx/work/OutOfQuotaPolicy.java
+++ b/work/work-runtime/src/main/java/androidx/work/OutOfQuotaPolicy.kt
@@ -13,14 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package androidx.work;
+package androidx.work
 
 /**
  * An enumeration of policies that help determine out of quota behavior for expedited jobs.
  */
-public enum OutOfQuotaPolicy {
-
+enum class OutOfQuotaPolicy {
     /**
      * When the app does not have any expedited job quota, the expedited work request will
      * fallback to a regular work request.
@@ -31,5 +29,5 @@
      * When the app does not have any expedited job quota, the expedited work request will
      * be dropped and no work requests are enqueued.
      */
-    DROP_WORK_REQUEST;
-}
+    DROP_WORK_REQUEST
+}
\ No newline at end of file
diff --git a/work/work-runtime/src/main/java/androidx/work/PeriodicWorkRequest.java b/work/work-runtime/src/main/java/androidx/work/PeriodicWorkRequest.java
deleted file mode 100644
index 0d1a219..0000000
--- a/work/work-runtime/src/main/java/androidx/work/PeriodicWorkRequest.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright 2018 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 static androidx.work.impl.utils.DurationApi26Impl.toMillisCompat;
-
-import android.annotation.SuppressLint;
-import android.os.Build;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
-
-import java.time.Duration;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A {@link WorkRequest} for repeating work.  This work executes multiple times until it is
- * cancelled, with the first execution happening immediately or as soon as the given
- * {@link Constraints} are met.  The next execution will happen during the period interval; note
- * that execution may be delayed because {@link WorkManager} is subject to OS battery optimizations,
- * such as doze mode.
- * <p>
- * You can control when the work executes in the period interval more exactly - see
- * {@link PeriodicWorkRequest.Builder} for documentation on {@code flexInterval}s.
- * <p>
- * Periodic work has a minimum interval of 15 minutes.
- * <p>
- * Periodic work is intended for use cases where you want a fairly consistent delay between
- * consecutive runs, and you are willing to accept inexactness due to battery optimizations and doze
- * mode.  Please note that if your periodic work has constraints, it will not execute until the
- * constraints are met, even if the delay between periods has been met.
- * <p>
- * If you need to schedule work that happens exactly at a certain time or only during a certain time
- * window, you should consider using {@link OneTimeWorkRequest}s.
- * <p>
- * The normal lifecycle of a PeriodicWorkRequest is {@code ENQUEUED -> RUNNING -> ENQUEUED}.  By
- * definition, periodic work cannot terminate in a succeeded or failed state, since it must recur.
- * It can only terminate if explicitly cancelled.  However, in the case of retries, periodic work
- * will still back off according to
- * {@link PeriodicWorkRequest.Builder#setBackoffCriteria(BackoffPolicy, long, TimeUnit)}.
- * <p>
- * Periodic work cannot be part of a chain or graph of work.
- */
-
-public final class PeriodicWorkRequest extends WorkRequest {
-
-    /**
-     * The minimum interval duration for {@link PeriodicWorkRequest} (in milliseconds).
-     */
-    @SuppressLint("MinMaxConstant")
-    public static final long MIN_PERIODIC_INTERVAL_MILLIS = 15 * 60 * 1000L; // 15 minutes.
-    /**
-     * The minimum flex duration for {@link PeriodicWorkRequest} (in milliseconds).
-     */
-    @SuppressLint("MinMaxConstant")
-    public static final long MIN_PERIODIC_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes.
-
-    PeriodicWorkRequest(Builder builder) {
-        super(builder.mId, builder.mWorkSpec, builder.mTags);
-    }
-
-    /**
-     * Builder for {@link PeriodicWorkRequest}s.
-     */
-    public static final class Builder extends WorkRequest.Builder<Builder, PeriodicWorkRequest> {
-
-        /**
-         * Creates a {@link PeriodicWorkRequest} to run periodically once every interval period. The
-         * {@link PeriodicWorkRequest} is guaranteed to run exactly one time during this interval
-         * (subject to OS battery optimizations, such as doze mode). The repeat interval must
-         * be greater than or equal to {@link PeriodicWorkRequest#MIN_PERIODIC_INTERVAL_MILLIS}. It
-         * may run immediately, at the end of the period, or any time in between so long as the
-         * other conditions are satisfied at the time. The run time of the
-         * {@link PeriodicWorkRequest} can be restricted to a flex period within an interval (see
-         * {@code #Builder(Class, long, TimeUnit, long, TimeUnit)}).
-         *
-         * @param workerClass The {@link ListenableWorker} class to run for this work
-         * @param repeatInterval The repeat interval in {@code repeatIntervalTimeUnit} units
-         * @param repeatIntervalTimeUnit The {@link TimeUnit} for {@code repeatInterval}
-         */
-        public Builder(
-                @NonNull Class<? extends ListenableWorker> workerClass,
-                long repeatInterval,
-                @NonNull TimeUnit repeatIntervalTimeUnit) {
-            super(workerClass);
-            mWorkSpec.setPeriodic(repeatIntervalTimeUnit.toMillis(repeatInterval));
-        }
-
-        /**
-         * Creates a {@link PeriodicWorkRequest} to run periodically once every interval period. The
-         * {@link PeriodicWorkRequest} is guaranteed to run exactly one time during this interval
-         * (subject to OS battery optimizations, such as doze mode). The repeat interval must
-         * be greater than or equal to {@link PeriodicWorkRequest#MIN_PERIODIC_INTERVAL_MILLIS}. It
-         * may run immediately, at the end of the period, or any time in between so long as the
-         * other conditions are satisfied at the time. The run time of the
-         * {@link PeriodicWorkRequest} can be restricted to a flex period within an interval (see
-         * {@code #Builder(Class, Duration, Duration)}).
-         *
-         * @param workerClass The {@link ListenableWorker} class to run for this work
-         * @param repeatInterval The repeat interval
-         */
-        @RequiresApi(26)
-        public Builder(
-                @NonNull Class<? extends ListenableWorker> workerClass,
-                @NonNull Duration repeatInterval) {
-            super(workerClass);
-            mWorkSpec.setPeriodic(toMillisCompat(repeatInterval));
-        }
-
-        /**
-         * Creates a {@link PeriodicWorkRequest} to run periodically once within the
-         * <strong>flex period</strong> of every interval period. See diagram below.  The flex
-         * period begins at {@code repeatInterval - flexInterval} to the end of the interval.
-         * The repeat interval must be greater than or equal to
-         * {@link PeriodicWorkRequest#MIN_PERIODIC_INTERVAL_MILLIS} and the flex interval must
-         * be greater than or equal to {@link PeriodicWorkRequest#MIN_PERIODIC_FLEX_MILLIS}.
-         *
-         * <p><pre>
-         * [     before flex     |     flex     ][     before flex     |     flex     ]...
-         * [   cannot run work   | can run work ][   cannot run work   | can run work ]...
-         * \____________________________________/\____________________________________/...
-         *                interval 1                            interval 2             ...(repeat)
-         * </pre></p>
-         *
-         * @param workerClass The {@link ListenableWorker} class to run for this work
-         * @param repeatInterval The repeat interval in {@code repeatIntervalTimeUnit} units
-         * @param repeatIntervalTimeUnit The {@link TimeUnit} for {@code repeatInterval}
-         * @param flexInterval The duration in {@code flexIntervalTimeUnit} units for which this
-         *                     work repeats from the end of the {@code repeatInterval}
-         * @param flexIntervalTimeUnit The {@link TimeUnit} for {@code flexInterval}
-         */
-        public Builder(
-                @NonNull Class<? extends ListenableWorker> workerClass,
-                long repeatInterval,
-                @NonNull TimeUnit repeatIntervalTimeUnit,
-                long flexInterval,
-                @NonNull TimeUnit flexIntervalTimeUnit) {
-            super(workerClass);
-            mWorkSpec.setPeriodic(
-                    repeatIntervalTimeUnit.toMillis(repeatInterval),
-                    flexIntervalTimeUnit.toMillis(flexInterval));
-        }
-
-        /**
-         * Creates a {@link PeriodicWorkRequest} to run periodically once within the
-         * <strong>flex period</strong> of every interval period. See diagram below.  The flex
-         * period begins at {@code repeatInterval - flexInterval} to the end of the interval.
-         * The repeat interval must be greater than or equal to
-         * {@link PeriodicWorkRequest#MIN_PERIODIC_INTERVAL_MILLIS} and the flex interval must
-         * be greater than or equal to {@link PeriodicWorkRequest#MIN_PERIODIC_FLEX_MILLIS}.
-         *
-         * <p><pre>
-         * [     before flex     |     flex     ][     before flex     |     flex     ]...
-         * [   cannot run work   | can run work ][   cannot run work   | can run work ]...
-         * \____________________________________/\____________________________________/...
-         *                interval 1                            interval 2             ...(repeat)
-         * </pre></p>
-         *
-         * @param workerClass The {@link ListenableWorker} class to run for this work
-         * @param repeatInterval The repeat interval
-         * @param flexInterval The duration in for which this work repeats from the end of the
-         *                     {@code repeatInterval}
-         */
-        @RequiresApi(26)
-        public Builder(
-                @NonNull Class<? extends ListenableWorker> workerClass,
-                @NonNull Duration repeatInterval,
-                @NonNull Duration flexInterval) {
-            super(workerClass);
-            mWorkSpec.setPeriodic(toMillisCompat(repeatInterval),
-                    toMillisCompat(flexInterval));
-        }
-
-        @Override
-        @NonNull PeriodicWorkRequest buildInternal() {
-            if (mBackoffCriteriaSet
-                    && Build.VERSION.SDK_INT >= 23
-                    && mWorkSpec.constraints.requiresDeviceIdle()) {
-                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);
-        }
-
-        @Override
-        @NonNull Builder getThis() {
-            return this;
-        }
-    }
-}
diff --git a/work/work-runtime/src/main/java/androidx/work/PeriodicWorkRequest.kt b/work/work-runtime/src/main/java/androidx/work/PeriodicWorkRequest.kt
new file mode 100644
index 0000000..f007495
--- /dev/null
+++ b/work/work-runtime/src/main/java/androidx/work/PeriodicWorkRequest.kt
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2018 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 android.annotation.SuppressLint
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.work.impl.utils.toMillisCompat
+import java.time.Duration
+import java.util.concurrent.TimeUnit
+
+/**
+ * A [WorkRequest] for repeating work.  This work executes multiple times until it is
+ * cancelled, with the first execution happening immediately or as soon as the given
+ * [Constraints] are met.  The next execution will happen during the period interval; note
+ * that execution may be delayed because [WorkManager] is subject to OS battery optimizations,
+ * such as doze mode.
+ *
+ * You can control when the work executes in the period interval more exactly - see
+ * [PeriodicWorkRequest.Builder] for documentation on `flexInterval`s.
+ *
+ * Periodic work has a minimum interval of 15 minutes.
+ *
+ * Periodic work is intended for use cases where you want a fairly consistent delay between
+ * consecutive runs, and you are willing to accept inexactness due to battery optimizations and doze
+ * mode.  Please note that if your periodic work has constraints, it will not execute until the
+ * constraints are met, even if the delay between periods has been met.
+ *
+ * If you need to schedule work that happens exactly at a certain time or only during a certain time
+ * window, you should consider using [OneTimeWorkRequest]s.
+ *
+ * The normal lifecycle of a PeriodicWorkRequest is `ENQUEUED -> RUNNING -> ENQUEUED`.  By
+ * definition, periodic work cannot terminate in a succeeded or failed state, since it must recur.
+ * It can only terminate if explicitly cancelled.  However, in the case of retries, periodic work
+ * will still back off according to [PeriodicWorkRequest.Builder.setBackoffCriteria].
+ *
+ * Periodic work cannot be part of a chain or graph of work.
+ */
+class PeriodicWorkRequest internal constructor(
+    builder: Builder
+) : WorkRequest(builder.id, builder.workSpec, builder.tags) {
+    /**
+     * Builder for [PeriodicWorkRequest]s.
+     */
+    class Builder : WorkRequest.Builder<Builder, PeriodicWorkRequest> {
+        /**
+         * Creates a [PeriodicWorkRequest] to run periodically once every interval period. The
+         * [PeriodicWorkRequest] is guaranteed to run exactly one time during this interval
+         * (subject to OS battery optimizations, such as doze mode). The repeat interval must
+         * be greater than or equal to [PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS]. It
+         * may run immediately, at the end of the period, or any time in between so long as the
+         * other conditions are satisfied at the time. The run time of the
+         * [PeriodicWorkRequest] can be restricted to a flex period within an interval (see
+         * `#Builder(Class, long, TimeUnit, long, TimeUnit)`).
+         *
+         * @param workerClass The [ListenableWorker] class to run for this work
+         * @param repeatInterval The repeat interval in `repeatIntervalTimeUnit` units
+         * @param repeatIntervalTimeUnit The [TimeUnit] for `repeatInterval`
+         */
+        constructor(
+            workerClass: Class<out ListenableWorker?>,
+            repeatInterval: Long,
+            repeatIntervalTimeUnit: TimeUnit
+        ) : super(workerClass) {
+            workSpec.setPeriodic(repeatIntervalTimeUnit.toMillis(repeatInterval))
+        }
+
+        /**
+         * Creates a [PeriodicWorkRequest] to run periodically once every interval period. The
+         * [PeriodicWorkRequest] is guaranteed to run exactly one time during this interval
+         * (subject to OS battery optimizations, such as doze mode). The repeat interval must
+         * be greater than or equal to [PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS]. It
+         * may run immediately, at the end of the period, or any time in between so long as the
+         * other conditions are satisfied at the time. The run time of the
+         * [PeriodicWorkRequest] can be restricted to a flex period within an interval (see
+         * `#Builder(Class, Duration, Duration)`).
+         *
+         * @param workerClass The [ListenableWorker] class to run for this work
+         * @param repeatInterval The repeat interval
+         */
+        @RequiresApi(26)
+        constructor(
+            workerClass: Class<out ListenableWorker>,
+            repeatInterval: Duration
+        ) : super(workerClass) {
+            workSpec.setPeriodic(repeatInterval.toMillisCompat())
+        }
+
+        /**
+         * Creates a [PeriodicWorkRequest] to run periodically once within the
+         * **flex period** of every interval period. See diagram below.  The flex
+         * period begins at `repeatInterval - flexInterval` to the end of the interval.
+         * The repeat interval must be greater than or equal to
+         * [PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS] and the flex interval must
+         * be greater than or equal to [PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS].
+         *  ```
+         * [_____before flex_____|_____flex_____][_____before flex_____|_____flex_____]...
+         * [___cannot run work___|_can run work_][___cannot run work___|_can run work_]...
+         * \____________________________________/\____________________________________/...
+         * interval 1                            interval 2             ...(repeat)
+         * ```
+         *
+         * @param workerClass The [ListenableWorker] class to run for this work
+         * @param repeatInterval The repeat interval in `repeatIntervalTimeUnit` units
+         * @param repeatIntervalTimeUnit The [TimeUnit] for `repeatInterval`
+         * @param flexInterval The duration in `flexIntervalTimeUnit` units for which this
+         * work repeats from the end of the `repeatInterval`
+         * @param flexIntervalTimeUnit The [TimeUnit] for `flexInterval`
+         */
+        constructor(
+            workerClass: Class<out ListenableWorker?>,
+            repeatInterval: Long,
+            repeatIntervalTimeUnit: TimeUnit,
+            flexInterval: Long,
+            flexIntervalTimeUnit: TimeUnit
+        ) : super(workerClass) {
+            workSpec.setPeriodic(
+                repeatIntervalTimeUnit.toMillis(repeatInterval),
+                flexIntervalTimeUnit.toMillis(flexInterval)
+            )
+        }
+
+        /**
+         * Creates a [PeriodicWorkRequest] to run periodically once within the
+         * **flex period** of every interval period. See diagram below.  The flex
+         * period begins at `repeatInterval - flexInterval` to the end of the interval.
+         * The repeat interval must be greater than or equal to
+         * [PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS] and the flex interval must
+         * be greater than or equal to [PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS].
+         *
+         *  ```
+         * [_____before flex_____|_____flex_____][_____before flex_____|_____flex_____]...
+         * [___cannot run work___|_can run work_][___cannot run work___|_can run work_]...
+         * \____________________________________/\____________________________________/...
+         * interval 1                            interval 2             ...(repeat)
+         * ```
+         *
+         * @param workerClass The [ListenableWorker] class to run for this work
+         * @param repeatInterval The repeat interval
+         * @param flexInterval The duration in for which this work repeats from the end of the
+         * `repeatInterval`
+         */
+        @RequiresApi(26)
+        constructor(
+            workerClass: Class<out ListenableWorker?>,
+            repeatInterval: Duration,
+            flexInterval: Duration
+        ) : super(workerClass) {
+            workSpec.setPeriodic(repeatInterval.toMillisCompat(), flexInterval.toMillisCompat())
+        }
+
+        override fun buildInternal(): PeriodicWorkRequest {
+            require(
+                !(backoffCriteriaSet && Build.VERSION.SDK_INT >= 23 &&
+                    workSpec.constraints.requiresDeviceIdle())
+            ) { "Cannot set backoff criteria on an idle mode job" }
+            require(!workSpec.expedited) { "PeriodicWorkRequests cannot be expedited" }
+            return PeriodicWorkRequest(this)
+        }
+
+        override val thisObject: Builder
+            get() = this
+    }
+
+    companion object {
+        /**
+         * The minimum interval duration for [PeriodicWorkRequest] (in milliseconds).
+         */
+        @SuppressLint("MinMaxConstant")
+        const val MIN_PERIODIC_INTERVAL_MILLIS = 15 * 60 * 1000L // 15 minutes.
+
+        /**
+         * The minimum flex duration for [PeriodicWorkRequest] (in milliseconds).
+         */
+        @SuppressLint("MinMaxConstant")
+        const val MIN_PERIODIC_FLEX_MILLIS = 5 * 60 * 1000L // 5 minutes.
+    }
+}
+
+/**
+ * Creates a [PeriodicWorkRequest.Builder] with a given [ListenableWorker].
+ *
+ * @param repeatInterval @see [androidx.work.PeriodicWorkRequest.Builder]
+ * @param repeatIntervalTimeUnit @see [androidx.work.PeriodicWorkRequest.Builder]
+ */
+public inline fun <reified W : ListenableWorker> PeriodicWorkRequestBuilder(
+    repeatInterval: Long,
+    repeatIntervalTimeUnit: TimeUnit
+): PeriodicWorkRequest.Builder {
+    return PeriodicWorkRequest.Builder(W::class.java, repeatInterval, repeatIntervalTimeUnit)
+}
+
+/**
+ * Creates a [PeriodicWorkRequest.Builder] with a given [ListenableWorker].
+ *
+ * @param repeatInterval @see [androidx.work.PeriodicWorkRequest.Builder]
+ */
+@RequiresApi(26)
+public inline fun <reified W : ListenableWorker> PeriodicWorkRequestBuilder(
+    repeatInterval: Duration
+): PeriodicWorkRequest.Builder {
+    return PeriodicWorkRequest.Builder(W::class.java, repeatInterval)
+}
+
+/**
+ * Creates a [PeriodicWorkRequest.Builder] with a given [ListenableWorker].
+ *
+ * @param repeatInterval @see [androidx.work.PeriodicWorkRequest.Builder]
+ * @param repeatIntervalTimeUnit @see [androidx.work.PeriodicWorkRequest.Builder]
+ * @param flexTimeInterval @see [androidx.work.PeriodicWorkRequest.Builder]
+ * @param flexTimeIntervalUnit @see [androidx.work.PeriodicWorkRequest.Builder]
+ */
+public inline fun <reified W : ListenableWorker> PeriodicWorkRequestBuilder(
+    repeatInterval: Long,
+    repeatIntervalTimeUnit: TimeUnit,
+    flexTimeInterval: Long,
+    flexTimeIntervalUnit: TimeUnit
+): PeriodicWorkRequest.Builder {
+
+    return PeriodicWorkRequest.Builder(
+        W::class.java,
+        repeatInterval,
+        repeatIntervalTimeUnit,
+        flexTimeInterval,
+        flexTimeIntervalUnit
+    )
+}
+
+/**
+ * Creates a [PeriodicWorkRequest.Builder] with a given [ListenableWorker].
+ *
+ * @param repeatInterval @see [androidx.work.PeriodicWorkRequest.Builder]
+ * @param flexTimeInterval @see [androidx.work.PeriodicWorkRequest.Builder]
+ */
+@RequiresApi(26)
+public inline fun <reified W : ListenableWorker> PeriodicWorkRequestBuilder(
+    repeatInterval: Duration,
+    flexTimeInterval: Duration
+): PeriodicWorkRequest.Builder {
+    return PeriodicWorkRequest.Builder(W::class.java, repeatInterval, flexTimeInterval)
+}
\ No newline at end of file
diff --git a/work/work-runtime/src/main/java/androidx/work/WorkRequest.java b/work/work-runtime/src/main/java/androidx/work/WorkRequest.java
deleted file mode 100644
index 6e9c7f5..0000000
--- a/work/work-runtime/src/main/java/androidx/work/WorkRequest.java
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * Copyright 2018 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 android.annotation.SuppressLint;
-import android.os.Build;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
-import androidx.annotation.RestrictTo;
-import androidx.annotation.VisibleForTesting;
-import androidx.work.impl.model.WorkSpec;
-import androidx.work.impl.utils.DurationApi26Impl;
-
-import java.time.Duration;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-
-/**
- * The base class for specifying parameters for work that should be enqueued in {@link WorkManager}.
- * There are two concrete implementations of this class: {@link OneTimeWorkRequest} and
- * {@link PeriodicWorkRequest}.
- */
-
-public abstract class WorkRequest {
-
-    /**
-     * The default initial backoff time (in milliseconds) for work that has to be retried.
-     */
-    public static final long DEFAULT_BACKOFF_DELAY_MILLIS = 30000L;
-
-    /**
-     * The maximum backoff time (in milliseconds) for work that has to be retried.
-     */
-    @SuppressLint("MinMaxConstant")
-    public static final long MAX_BACKOFF_MILLIS = 5 * 60 * 60 * 1000; // 5 hours.
-
-    /**
-     * The minimum backoff time for work (in milliseconds) that has to be retried.
-     */
-    @SuppressLint("MinMaxConstant")
-    public static final long MIN_BACKOFF_MILLIS = 10 * 1000; // 10 seconds.
-
-    private @NonNull UUID mId;
-    private @NonNull WorkSpec mWorkSpec;
-    private @NonNull Set<String> mTags;
-
-    /**
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    protected WorkRequest(@NonNull UUID id, @NonNull WorkSpec workSpec, @NonNull Set<String> tags) {
-        mId = id;
-        mWorkSpec = workSpec;
-        mTags = tags;
-    }
-
-    /**
-     * Gets the unique identifier associated with this unit of work.
-     *
-     * @return The identifier for this unit of work
-     */
-    public @NonNull UUID getId() {
-        return mId;
-    }
-
-    /**
-     * Gets the string for the unique identifier associated with this unit of work.
-     *
-     * @return The string identifier for this unit of work
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    public @NonNull String getStringId() {
-        return mId.toString();
-    }
-
-    /**
-     * Gets the {@link WorkSpec} associated with this unit of work.
-     *
-     * @return The {@link WorkSpec} for this unit of work
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    public @NonNull WorkSpec getWorkSpec() {
-        return mWorkSpec;
-    }
-
-    /**
-     * Gets the tags associated with this unit of work.
-     *
-     * @return The tags for this unit of work
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    public @NonNull Set<String> getTags() {
-        return mTags;
-    }
-
-    /**
-     * A builder for {@link WorkRequest}s.  There are two concrete implementations of this class:
-     * {@link OneTimeWorkRequest.Builder} and {@link PeriodicWorkRequest.Builder}.
-     *
-     * @param <B> The concrete implementation of this Builder
-     * @param <W> The type of work object built by this Builder
-     */
-    public abstract static class Builder<B extends Builder<?, ?>, W extends WorkRequest> {
-
-        boolean mBackoffCriteriaSet = false;
-        UUID mId;
-        WorkSpec mWorkSpec;
-        Set<String> mTags = new HashSet<>();
-        Class<? extends ListenableWorker> mWorkerClass;
-
-        Builder(@NonNull Class<? extends ListenableWorker> workerClass) {
-            mId = UUID.randomUUID();
-            mWorkerClass = workerClass;
-            mWorkSpec = new WorkSpec(mId.toString(), workerClass.getName());
-            addTag(workerClass.getName());
-        }
-
-        /**
-         * Sets the backoff policy and backoff delay for the work.  The default values are
-         * {@link BackoffPolicy#EXPONENTIAL} and
-         * {@value WorkRequest#DEFAULT_BACKOFF_DELAY_MILLIS}, respectively.  {@code backoffDelay}
-         * will be clamped between {@link WorkRequest#MIN_BACKOFF_MILLIS} and
-         * {@link WorkRequest#MAX_BACKOFF_MILLIS}.
-         *
-         * @param backoffPolicy The {@link BackoffPolicy} to use when increasing backoff time
-         * @param backoffDelay Time to wait before retrying the work in {@code timeUnit} units
-         * @param timeUnit The {@link TimeUnit} for {@code backoffDelay}
-         * @return The current {@link Builder}
-         */
-        public final @NonNull B setBackoffCriteria(
-                @NonNull BackoffPolicy backoffPolicy,
-                long backoffDelay,
-                @NonNull TimeUnit timeUnit) {
-            mBackoffCriteriaSet = true;
-            mWorkSpec.backoffPolicy = backoffPolicy;
-            mWorkSpec.setBackoffDelayDuration(timeUnit.toMillis(backoffDelay));
-            return getThis();
-        }
-
-        /**
-         * Sets the backoff policy and backoff delay for the work.  The default values are
-         * {@link BackoffPolicy#EXPONENTIAL} and
-         * {@value WorkRequest#DEFAULT_BACKOFF_DELAY_MILLIS}, respectively.  {@code duration} will
-         * be clamped between {@link WorkRequest#MIN_BACKOFF_MILLIS} and
-         * {@link WorkRequest#MAX_BACKOFF_MILLIS}.
-         *
-         * @param backoffPolicy The {@link BackoffPolicy} to use when increasing backoff time
-         * @param duration Time to wait before retrying the work
-         * @return The current {@link Builder}
-         */
-        @RequiresApi(26)
-        public final @NonNull B setBackoffCriteria(
-                @NonNull BackoffPolicy backoffPolicy,
-                @NonNull Duration duration) {
-            mBackoffCriteriaSet = true;
-            mWorkSpec.backoffPolicy = backoffPolicy;
-            mWorkSpec.setBackoffDelayDuration(DurationApi26Impl.toMillisCompat(duration));
-            return getThis();
-        }
-
-        /**
-         * Adds constraints to the {@link WorkRequest}.
-         *
-         * @param constraints The constraints for the work
-         * @return The current {@link Builder}
-         */
-        public final @NonNull B setConstraints(@NonNull Constraints constraints) {
-            mWorkSpec.constraints = constraints;
-            return getThis();
-        }
-
-        /**
-         * Adds input {@link Data} to the work.  If a worker has prerequisites in its chain, this
-         * Data will be merged with the outputs of the prerequisites using an {@link InputMerger}.
-         *
-         * @param inputData key/value pairs that will be provided to the worker
-         * @return The current {@link Builder}
-         */
-        public final @NonNull B setInputData(@NonNull Data inputData) {
-            mWorkSpec.input = inputData;
-            return getThis();
-        }
-
-        /**
-         * Adds a tag for the work.  You can query and cancel work by tags.  Tags are particularly
-         * useful for modules or libraries to find and operate on their own work.
-         *
-         * @param tag A tag for identifying the work in queries.
-         * @return The current {@link Builder}
-         */
-        public final @NonNull B addTag(@NonNull String tag) {
-            mTags.add(tag);
-            return getThis();
-        }
-
-        /**
-         * Specifies that the results of this work should be kept for at least the specified amount
-         * of time.  After this time has elapsed, the results <b>may</b> be pruned at the discretion
-         * of WorkManager when there are no pending dependent jobs.
-         * <p>
-         * When the results of a work are pruned, it becomes impossible to query for its
-         * {@link WorkInfo}.
-         * <p>
-         * Specifying a long duration here may adversely affect performance in terms of app storage
-         * and database query time.
-         *
-         * @param duration The minimum duration of time (in {@code timeUnit} units) to keep the
-         *                 results of this work
-         * @param timeUnit The unit of time for {@code duration}
-         * @return The current {@link Builder}
-         */
-        public final @NonNull B keepResultsForAtLeast(long duration, @NonNull TimeUnit timeUnit) {
-            mWorkSpec.minimumRetentionDuration = timeUnit.toMillis(duration);
-            return getThis();
-        }
-
-        /**
-         * Specifies that the results of this work should be kept for at least the specified amount
-         * of time.  After this time has elapsed, the results <p>may</p> be pruned at the discretion
-         * of WorkManager when this WorkRequest has reached a finished state (see
-         * {@link WorkInfo.State#isFinished()}) and there are no pending dependent jobs.
-         * <p>
-         * When the results of a work are pruned, it becomes impossible to query for its
-         * {@link WorkInfo}.
-         * <p>
-         * Specifying a long duration here may adversely affect performance in terms of app storage
-         * and database query time.
-         *
-         * @param duration The minimum duration of time to keep the results of this work
-         * @return The current {@link Builder}
-         */
-        @RequiresApi(26)
-        public final @NonNull B keepResultsForAtLeast(@NonNull Duration duration) {
-            mWorkSpec.minimumRetentionDuration = DurationApi26Impl.toMillisCompat(duration);
-            return getThis();
-        }
-
-        /**
-         * Sets an initial delay for the {@link WorkRequest}.
-         *
-         * @param duration The length of the delay in {@code timeUnit} units
-         * @param timeUnit The units of time for {@code duration}
-         * @return The current {@link Builder}
-         * @throws IllegalArgumentException if the given initial delay will push the execution time
-         *         past {@code Long.MAX_VALUE} and cause an overflow
-         */
-        public @NonNull B setInitialDelay(long duration, @NonNull TimeUnit timeUnit) {
-            mWorkSpec.initialDelay = timeUnit.toMillis(duration);
-            if (Long.MAX_VALUE - System.currentTimeMillis() <= mWorkSpec.initialDelay) {
-                throw new IllegalArgumentException("The given initial delay is too large and will"
-                        + " cause an overflow!");
-            }
-            return getThis();
-        }
-
-        /**
-         * Sets an initial delay for the {@link WorkRequest}.
-         *
-         * @param duration The length of the delay
-         * @return The current {@link Builder}         *
-         * @throws IllegalArgumentException if the given initial delay will push the execution time
-         *         past {@code Long.MAX_VALUE} and cause an overflow
-         */
-        @RequiresApi(26)
-        public @NonNull B setInitialDelay(@NonNull Duration duration) {
-            mWorkSpec.initialDelay = DurationApi26Impl.toMillisCompat(duration);
-            if (Long.MAX_VALUE - System.currentTimeMillis() <= mWorkSpec.initialDelay) {
-                throw new IllegalArgumentException("The given initial delay is too large and will"
-                        + " cause an overflow!");
-            }
-            return getThis();
-        }
-
-        /**
-         * Marks the {@link WorkRequest} as important to the user.  In this case, WorkManager
-         * provides an additional signal to the OS that this work is important.
-         *
-         * @param policy The {@link OutOfQuotaPolicy} to be used.
-         */
-        @SuppressLint("MissingGetterMatchingBuilder")
-        public @NonNull B setExpedited(@NonNull OutOfQuotaPolicy policy) {
-            mWorkSpec.expedited = true;
-            mWorkSpec.outOfQuotaPolicy = policy;
-            return getThis();
-        }
-
-        /**
-         * Builds a {@link WorkRequest} based on this {@link Builder}.
-         *
-         * @return A {@link WorkRequest} based on this {@link Builder}
-         */
-        public final @NonNull W build() {
-            W returnValue = buildInternal();
-            Constraints constraints = mWorkSpec.constraints;
-            // Check for unsupported constraints.
-            boolean hasUnsupportedConstraints =
-                    (Build.VERSION.SDK_INT >= 24 && constraints.hasContentUriTriggers())
-                            || constraints.requiresBatteryNotLow()
-                            || constraints.requiresCharging()
-                            || (Build.VERSION.SDK_INT >= 23 && constraints.requiresDeviceIdle());
-
-            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();
-            mWorkSpec = new WorkSpec(mId.toString(), mWorkSpec);
-            return returnValue;
-        }
-
-        abstract @NonNull W buildInternal();
-
-        abstract @NonNull B getThis();
-
-        /**
-         * Sets the initial state for this work.  Used in testing only.
-         *
-         * @param state The {@link WorkInfo.State} to set
-         * @return The current {@link Builder}
-         * @hide
-         */
-        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-        @VisibleForTesting
-        public final @NonNull B setInitialState(@NonNull WorkInfo.State state) {
-            mWorkSpec.state = state;
-            return getThis();
-        }
-
-        /**
-         * Sets the initial run attempt count for this work.  Used in testing only.
-         *
-         * @param runAttemptCount The initial run attempt count
-         * @return The current {@link Builder}
-         * @hide
-         */
-        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-        @VisibleForTesting
-        public final @NonNull B setInitialRunAttemptCount(int runAttemptCount) {
-            mWorkSpec.runAttemptCount = runAttemptCount;
-            return getThis();
-        }
-
-        /**
-         * Sets the period start time for this work. Used in testing only.
-         *
-         * @param periodStartTime the period start time in {@code timeUnit} units
-         * @param timeUnit The {@link TimeUnit} for {@code periodStartTime}
-         * @return The current {@link Builder}
-         * @hide
-         */
-        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-        @VisibleForTesting
-        @NonNull
-        public final B setLastEnqueueTime(
-                long periodStartTime,
-                @NonNull TimeUnit timeUnit) {
-            mWorkSpec.lastEnqueueTime = timeUnit.toMillis(periodStartTime);
-            return getThis();
-        }
-
-        /**
-         * Sets when the scheduler actually schedules the worker.
-         *
-         * @param scheduleRequestedAt The time at which the scheduler scheduled a worker.
-         * @param timeUnit            The {@link TimeUnit} for {@code scheduleRequestedAt}
-         * @return The current {@link Builder}
-         * @hide
-         */
-        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-        @VisibleForTesting
-        public final @NonNull B setScheduleRequestedAt(
-                long scheduleRequestedAt,
-                @NonNull TimeUnit timeUnit) {
-            mWorkSpec.scheduleRequestedAt = timeUnit.toMillis(scheduleRequestedAt);
-            return getThis();
-        }
-    }
-}
diff --git a/work/work-runtime/src/main/java/androidx/work/WorkRequest.kt b/work/work-runtime/src/main/java/androidx/work/WorkRequest.kt
new file mode 100644
index 0000000..21d240f
--- /dev/null
+++ b/work/work-runtime/src/main/java/androidx/work/WorkRequest.kt
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2018 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 android.annotation.SuppressLint
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+import androidx.annotation.VisibleForTesting
+import androidx.work.impl.utils.toMillisCompat
+import androidx.work.impl.model.WorkSpec
+import java.time.Duration
+import java.util.UUID
+import java.util.concurrent.TimeUnit
+
+/**
+ * The base class for specifying parameters for work that should be enqueued in [WorkManager].
+ * There are two concrete implementations of this class: [OneTimeWorkRequest] and
+ * [PeriodicWorkRequest].
+ */
+abstract class WorkRequest internal constructor(
+    /**
+     * The unique identifier associated with this unit of work.
+     */
+    open val id: UUID,
+    /**
+     * The [WorkSpec] associated with this unit of work.
+     *
+     * @hide
+     */
+    @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    val workSpec: WorkSpec,
+    /**
+     * The tags associated with this unit of work.
+     *
+     */
+    @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    val tags: Set<String>
+) {
+
+    /**
+     * Gets the string for the unique identifier associated with this unit of work.
+     *
+     * @return The string identifier for this unit of work
+     * @hide
+     */
+    @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    val stringId: String
+        get() = id.toString()
+
+    /**
+     * A builder for [WorkRequest]s.  There are two concrete implementations of this class:
+     * [OneTimeWorkRequest.Builder] and [PeriodicWorkRequest.Builder].
+     */
+    abstract class Builder<B : Builder<B, *>, W : WorkRequest> internal constructor(
+        internal val workerClass: Class<out ListenableWorker>
+    ) {
+        internal var backoffCriteriaSet = false
+        internal var id: UUID = UUID.randomUUID()
+        internal var workSpec: WorkSpec = WorkSpec(id.toString(), workerClass.name)
+        internal val tags: MutableSet<String> = mutableSetOf(workerClass.name)
+
+        /**
+         * Sets the backoff policy and backoff delay for the work.  The default values are
+         * [BackoffPolicy.EXPONENTIAL] and
+         * {@value WorkRequest#DEFAULT_BACKOFF_DELAY_MILLIS}, respectively.  `backoffDelay`
+         * will be clamped between [WorkRequest.MIN_BACKOFF_MILLIS] and
+         * [WorkRequest.MAX_BACKOFF_MILLIS].
+         *
+         * @param backoffPolicy The [BackoffPolicy] to use when increasing backoff time
+         * @param backoffDelay Time to wait before retrying the work in `timeUnit` units
+         * @param timeUnit The [TimeUnit] for `backoffDelay`
+         * @return The current [Builder]
+         */
+        fun setBackoffCriteria(
+            backoffPolicy: BackoffPolicy,
+            backoffDelay: Long,
+            timeUnit: TimeUnit
+        ): B {
+            backoffCriteriaSet = true
+            workSpec.backoffPolicy = backoffPolicy
+            workSpec.setBackoffDelayDuration(timeUnit.toMillis(backoffDelay))
+            return thisObject
+        }
+
+        /**
+         * Sets the backoff policy and backoff delay for the work.  The default values are
+         * [BackoffPolicy.EXPONENTIAL] and
+         * {@value WorkRequest#DEFAULT_BACKOFF_DELAY_MILLIS}, respectively.  `duration` will
+         * be clamped between [WorkRequest.MIN_BACKOFF_MILLIS] and
+         * [WorkRequest.MAX_BACKOFF_MILLIS].
+         *
+         * @param backoffPolicy The [BackoffPolicy] to use when increasing backoff time
+         * @param duration Time to wait before retrying the work
+         * @return The current [Builder]
+         */
+        @RequiresApi(26)
+        fun setBackoffCriteria(backoffPolicy: BackoffPolicy, duration: Duration): B {
+            backoffCriteriaSet = true
+            workSpec.backoffPolicy = backoffPolicy
+            workSpec.setBackoffDelayDuration(duration.toMillisCompat())
+            return thisObject
+        }
+
+        /**
+         * Adds constraints to the [WorkRequest].
+         *
+         * @param constraints The constraints for the work
+         * @return The current [Builder]
+         */
+        fun setConstraints(constraints: Constraints): B {
+            workSpec.constraints = constraints
+            return thisObject
+        }
+
+        /**
+         * Adds input [Data] to the work.  If a worker has prerequisites in its chain, this
+         * Data will be merged with the outputs of the prerequisites using an [InputMerger].
+         *
+         * @param inputData key/value pairs that will be provided to the worker
+         * @return The current [Builder]
+         */
+        fun setInputData(inputData: Data): B {
+            workSpec.input = inputData
+            return thisObject
+        }
+
+        /**
+         * Adds a tag for the work.  You can query and cancel work by tags.  Tags are particularly
+         * useful for modules or libraries to find and operate on their own work.
+         *
+         * @param tag A tag for identifying the work in queries.
+         * @return The current [Builder]
+         */
+        fun addTag(tag: String): B {
+            tags.add(tag)
+            return thisObject
+        }
+
+        /**
+         * Specifies that the results of this work should be kept for at least the specified amount
+         * of time.  After this time has elapsed, the results **may** be pruned at the discretion
+         * of WorkManager when there are no pending dependent jobs.
+         *
+         * When the results of a work are pruned, it becomes impossible to query for its
+         * [WorkInfo].
+         *
+         * Specifying a long duration here may adversely affect performance in terms of app storage
+         * and database query time.
+         *
+         * @param duration The minimum duration of time (in `timeUnit` units) to keep the
+         * results of this work
+         * @param timeUnit The unit of time for `duration`
+         * @return The current [Builder]
+         */
+        fun keepResultsForAtLeast(duration: Long, timeUnit: TimeUnit): B {
+            workSpec.minimumRetentionDuration = timeUnit.toMillis(duration)
+            return thisObject
+        }
+
+        /**
+         * Specifies that the results of this work should be kept for at least the specified amount
+         * of time.  After this time has elapsed, the results may be pruned at the discretion
+         * of WorkManager when this WorkRequest has reached a finished state (see
+         * [WorkInfo.State.isFinished]) and there are no pending dependent jobs.
+         *
+         * When the results of a work are pruned, it becomes impossible to query for its
+         * [WorkInfo].
+         *
+         * Specifying a long duration here may adversely affect performance in terms of app storage
+         * and database query time.
+         *
+         * @param duration The minimum duration of time to keep the results of this work
+         * @return The current [Builder]
+         */
+        @RequiresApi(26)
+        fun keepResultsForAtLeast(duration: Duration): B {
+            workSpec.minimumRetentionDuration = duration.toMillisCompat()
+            return thisObject
+        }
+
+        /**
+         * Sets an initial delay for the [WorkRequest].
+         *
+         * @param duration The length of the delay in `timeUnit` units
+         * @param timeUnit The units of time for `duration`
+         * @return The current [Builder]
+         * @throws IllegalArgumentException if the given initial delay will push the execution time
+         * past `Long.MAX_VALUE` and cause an overflow
+         */
+        open fun setInitialDelay(duration: Long, timeUnit: TimeUnit): B {
+            workSpec.initialDelay = timeUnit.toMillis(duration)
+            require(Long.MAX_VALUE - System.currentTimeMillis() > workSpec.initialDelay) {
+                ("The given initial delay is too large and will cause an overflow!")
+            }
+            return thisObject
+        }
+
+        /**
+         * Sets an initial delay for the [WorkRequest].
+         *
+         * @param duration The length of the delay
+         * @return The current [Builder]         *
+         * @throws IllegalArgumentException if the given initial delay will push the execution time
+         * past `Long.MAX_VALUE` and cause an overflow
+         */
+        @RequiresApi(26)
+        open fun setInitialDelay(duration: Duration): B {
+            workSpec.initialDelay = duration.toMillisCompat()
+            require(Long.MAX_VALUE - System.currentTimeMillis() > workSpec.initialDelay) {
+                "The given initial delay is too large and will cause an overflow!"
+            }
+            return thisObject
+        }
+
+        /**
+         * Marks the [WorkRequest] as important to the user.  In this case, WorkManager
+         * provides an additional signal to the OS that this work is important.
+         *
+         * @param policy The [OutOfQuotaPolicy] to be used.
+         */
+        @SuppressLint("MissingGetterMatchingBuilder")
+        open fun setExpedited(policy: OutOfQuotaPolicy): B {
+            workSpec.expedited = true
+            workSpec.outOfQuotaPolicy = policy
+            return thisObject
+        }
+
+        /**
+         * Builds a [WorkRequest] based on this [Builder].
+         *
+         * @return A [WorkRequest] based on this [Builder]
+         */
+        fun build(): W {
+            val returnValue = buildInternal()
+            val constraints = workSpec.constraints
+            // Check for unsupported constraints.
+            val hasUnsupportedConstraints =
+                (Build.VERSION.SDK_INT >= 24 && constraints.hasContentUriTriggers() ||
+                    constraints.requiresBatteryNotLow() ||
+                    constraints.requiresCharging() ||
+                    Build.VERSION.SDK_INT >= 23 && constraints.requiresDeviceIdle())
+            if (workSpec.expedited) {
+                require(!hasUnsupportedConstraints) {
+                    "Expedited jobs only support network and storage constraints"
+                }
+                require(workSpec.initialDelay <= 0) { "Expedited jobs cannot be delayed" }
+            }
+            // Create a new id and WorkSpec so this WorkRequest.Builder can be used multiple times.
+            id = UUID.randomUUID()
+            workSpec = WorkSpec(id.toString(), workSpec)
+            return returnValue
+        }
+
+        internal abstract fun buildInternal(): W
+
+        internal abstract val thisObject: B
+
+        /**
+         * Sets the initial state for this work.  Used in testing only.
+         *
+         * @param state The [WorkInfo.State] to set
+         * @return The current [Builder]
+         * @hide
+         */
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        @VisibleForTesting
+        fun setInitialState(state: WorkInfo.State): B {
+            workSpec.state = state
+            return thisObject
+        }
+
+        /**
+         * Sets the initial run attempt count for this work.  Used in testing only.
+         *
+         * @param runAttemptCount The initial run attempt count
+         * @return The current [Builder]
+         * @hide
+         */
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        @VisibleForTesting
+        fun setInitialRunAttemptCount(runAttemptCount: Int): B {
+            workSpec.runAttemptCount = runAttemptCount
+            return thisObject
+        }
+
+        /**
+         * Sets the period start time for this work. Used in testing only.
+         *
+         * @param periodStartTime the period start time in `timeUnit` units
+         * @param timeUnit The [TimeUnit] for `periodStartTime`
+         * @return The current [Builder]
+         * @hide
+         */
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        @VisibleForTesting
+        fun setLastEnqueueTime(periodStartTime: Long, timeUnit: TimeUnit): B {
+            workSpec.lastEnqueueTime = timeUnit.toMillis(periodStartTime)
+            return thisObject
+        }
+
+        /**
+         * Sets when the scheduler actually schedules the worker.
+         *
+         * @param scheduleRequestedAt The time at which the scheduler scheduled a worker.
+         * @param timeUnit The [TimeUnit] for `scheduleRequestedAt`
+         * @return The current [Builder]
+         * @hide
+         */
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        @VisibleForTesting
+        fun setScheduleRequestedAt(scheduleRequestedAt: Long, timeUnit: TimeUnit): B {
+            workSpec.scheduleRequestedAt = timeUnit.toMillis(scheduleRequestedAt)
+            return thisObject
+        }
+    }
+
+    companion object {
+        /**
+         * The default initial backoff time (in milliseconds) for work that has to be retried.
+         */
+        const val DEFAULT_BACKOFF_DELAY_MILLIS = 30000L
+
+        /**
+         * The maximum backoff time (in milliseconds) for work that has to be retried.
+         */
+        @SuppressLint("MinMaxConstant")
+        const val MAX_BACKOFF_MILLIS = 5 * 60 * 60 * 1000L // 5 hours
+
+        /**
+         * The minimum backoff time for work (in milliseconds) that has to be retried.
+         */
+        @SuppressLint("MinMaxConstant")
+        const val MIN_BACKOFF_MILLIS = 10 * 1000L // 10 seconds.
+    }
+}
\ No newline at end of file
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/model/WorkSpec.kt b/work/work-runtime/src/main/java/androidx/work/impl/model/WorkSpec.kt
index 25e6d2e..fc6dbf2 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/model/WorkSpec.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/model/WorkSpec.kt
@@ -29,8 +29,8 @@
 import androidx.work.Data
 import androidx.work.Logger
 import androidx.work.OutOfQuotaPolicy
-import androidx.work.PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS
-import androidx.work.PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS
+import androidx.work.PeriodicWorkRequest.Companion.MIN_PERIODIC_FLEX_MILLIS
+import androidx.work.PeriodicWorkRequest.Companion.MIN_PERIODIC_INTERVAL_MILLIS
 import androidx.work.WorkInfo
 import androidx.work.WorkRequest
 import java.util.UUID
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/utils/EnqueueRunnable.java b/work/work-runtime/src/main/java/androidx/work/impl/utils/EnqueueRunnable.java
index 5831aed..977793e 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/utils/EnqueueRunnable.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/utils/EnqueueRunnable.java
@@ -25,7 +25,7 @@
 import static androidx.work.WorkInfo.State.FAILED;
 import static androidx.work.WorkInfo.State.RUNNING;
 import static androidx.work.WorkInfo.State.SUCCEEDED;
-import static androidx.work.impl.workers.ConstraintTrackingWorker.ARGUMENT_CLASS_NAME;
+import static androidx.work.impl.workers.ConstraintTrackingWorkerKt.ARGUMENT_CLASS_NAME;
 
 import android.content.Context;
 import android.os.Build;
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/utils/ProcessUtils.java b/work/work-runtime/src/main/java/androidx/work/impl/utils/ProcessUtils.java
deleted file mode 100644
index e8256dc..0000000
--- a/work/work-runtime/src/main/java/androidx/work/impl/utils/ProcessUtils.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2020 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.impl.utils;
-
-
-import static android.content.Context.ACTIVITY_SERVICE;
-import static android.os.Build.VERSION.SDK_INT;
-
-import android.annotation.SuppressLint;
-import android.app.ActivityManager;
-import android.app.Application;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.os.Process;
-import android.text.TextUtils;
-
-import androidx.annotation.DoNotInline;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
-import androidx.annotation.RestrictTo;
-import androidx.work.Configuration;
-import androidx.work.Logger;
-import androidx.work.WorkManager;
-
-import java.lang.reflect.Method;
-import java.util.List;
-
-/**
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class ProcessUtils {
-    private static final String TAG = Logger.tagWithPrefix("ProcessUtils");
-
-    private ProcessUtils() {
-        // Does nothing
-    }
-
-    /**
-     * @return {@code true} when {@link WorkManager} is running in the configured app process.
-     */
-    public static boolean isDefaultProcess(
-            @NonNull Context context,
-            @NonNull Configuration configuration) {
-
-        String processName = getProcessName(context);
-
-        if (!TextUtils.isEmpty(configuration.getDefaultProcessName())) {
-            return TextUtils.equals(processName, configuration.getDefaultProcessName());
-        } else {
-            ApplicationInfo info = context.getApplicationInfo();
-            return TextUtils.equals(processName, info.processName);
-        }
-    }
-
-    /**
-     * @return The name of the active process.
-     */
-    @Nullable
-    @SuppressLint({"PrivateApi", "DiscouragedPrivateApi"})
-    public static String getProcessName(@NonNull Context context) {
-        if (SDK_INT >= 28) {
-            return Api28Impl.getProcessName();
-        }
-
-        // Try using ActivityThread to determine the current process name.
-        try {
-            Class<?> activityThread = Class.forName(
-                    "android.app.ActivityThread",
-                    false,
-                    ProcessUtils.class.getClassLoader());
-            final Object packageName;
-            if (SDK_INT >= 18) {
-                Method currentProcessName = activityThread.getDeclaredMethod("currentProcessName");
-                currentProcessName.setAccessible(true);
-                packageName = currentProcessName.invoke(null);
-            } else {
-                Method getActivityThread = activityThread.getDeclaredMethod(
-                        "currentActivityThread");
-                getActivityThread.setAccessible(true);
-                Method getProcessName = activityThread.getDeclaredMethod("getProcessName");
-                getProcessName.setAccessible(true);
-                packageName = getProcessName.invoke(getActivityThread.invoke(null));
-            }
-            if (packageName instanceof String) {
-                return (String) packageName;
-            }
-        } catch (Throwable exception) {
-            Logger.get().debug(TAG, "Unable to check ActivityThread for processName", exception);
-        }
-
-        // Fallback to the most expensive way
-        int pid = Process.myPid();
-        ActivityManager am =
-                (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
-
-        if (am != null) {
-            List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
-            if (processes != null && !processes.isEmpty()) {
-                for (ActivityManager.RunningAppProcessInfo process : processes) {
-                    if (process.pid == pid) {
-                        return process.processName;
-                    }
-                }
-            }
-        }
-
-        return null;
-    }
-
-    @RequiresApi(28)
-    static class Api28Impl {
-        private Api28Impl() {
-            // This class is not instantiable.
-        }
-
-        @DoNotInline
-        static String getProcessName() {
-            return Application.getProcessName();
-        }
-    }
-}
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/utils/ProcessUtils.kt b/work/work-runtime/src/main/java/androidx/work/impl/utils/ProcessUtils.kt
new file mode 100644
index 0000000..135686d
--- /dev/null
+++ b/work/work-runtime/src/main/java/androidx/work/impl/utils/ProcessUtils.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2020 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.
+ */
+@file:JvmName("ProcessUtils")
+
+package androidx.work.impl.utils
+
+import android.annotation.SuppressLint
+import android.app.ActivityManager
+import android.app.Application
+import android.content.Context
+import android.os.Build
+import android.os.Process
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
+import androidx.work.Configuration
+import androidx.work.Logger
+import androidx.work.WorkManager
+
+private val TAG = Logger.tagWithPrefix("ProcessUtils")
+
+/**
+ * @return `true` when `WorkManager` is running in the configured app process.
+ */
+fun isDefaultProcess(context: Context, configuration: Configuration): Boolean {
+    val processName = getProcessName(context)
+    return if (!configuration.defaultProcessName.isNullOrEmpty()) {
+        processName == configuration.defaultProcessName
+    } else {
+        processName == context.applicationInfo.processName
+    }
+}
+
+/**
+ * @return The name of the active process.
+ */
+@SuppressLint("PrivateApi", "DiscouragedPrivateApi")
+private fun getProcessName(context: Context): String? {
+    if (Build.VERSION.SDK_INT >= 28) return Api28Impl.processName
+
+    // Try using ActivityThread to determine the current process name.
+    try {
+        val activityThread = Class.forName(
+            "android.app.ActivityThread",
+            false,
+            WorkManager::class.java.classLoader
+        )
+        val packageName = if (Build.VERSION.SDK_INT >= 18) {
+            val currentProcessName = activityThread.getDeclaredMethod("currentProcessName")
+            currentProcessName.isAccessible = true
+            currentProcessName.invoke(null)!!
+        } else {
+            val getActivityThread = activityThread.getDeclaredMethod("currentActivityThread")
+            getActivityThread.isAccessible = true
+            val getProcessName = activityThread.getDeclaredMethod("getProcessName")
+            getProcessName.isAccessible = true
+            getProcessName.invoke(getActivityThread.invoke(null))!!
+        }
+        if (packageName is String) return packageName
+    } catch (exception: Throwable) {
+        Logger.get().debug(TAG, "Unable to check ActivityThread for processName", exception)
+    }
+
+    // Fallback to the most expensive way
+    val pid = Process.myPid()
+    val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
+    return am.runningAppProcesses?.find { process -> process.pid == pid }?.processName
+}
+
+@RequiresApi(28)
+private object Api28Impl {
+    @get:DoNotInline
+    val processName: String
+        get() = Application.getProcessName()
+}
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/utils/WakeLocks.java b/work/work-runtime/src/main/java/androidx/work/impl/utils/WakeLocks.java
deleted file mode 100644
index 652cef9..0000000
--- a/work/work-runtime/src/main/java/androidx/work/impl/utils/WakeLocks.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2018 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.impl.utils;
-
-import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
-
-import android.content.Context;
-import android.os.PowerManager;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.work.Logger;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.WeakHashMap;
-
-/**
- * A common class for creating WakeLocks.
- *
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class WakeLocks {
-
-    private static final String TAG = Logger.tagWithPrefix("WakeLocks");
-
-    private static final WeakHashMap<PowerManager.WakeLock, String> sWakeLocks =
-            new WeakHashMap<>();
-
-    /**
-     * Creates and returns a new WakeLock.
-     *
-     * @param context The context from which to get the PowerManager
-     * @param tag     A descriptive tag for the WakeLock; this method will prefix "WorkManager: "
-     *                to it
-     * @return A new {@link android.os.PowerManager.WakeLock}
-     */
-    public static PowerManager.WakeLock newWakeLock(
-            @NonNull Context context,
-            @NonNull String tag) {
-        PowerManager powerManager = (PowerManager) context.getApplicationContext()
-                .getSystemService(Context.POWER_SERVICE);
-
-        String tagWithPrefix = "WorkManager: " + tag;
-        PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PARTIAL_WAKE_LOCK, tagWithPrefix);
-        // Wakelocks are created on the command processor thread, but we check if they are still
-        // being held on the main thread.
-        synchronized (sWakeLocks) {
-            sWakeLocks.put(wakeLock, tagWithPrefix);
-        }
-        return wakeLock;
-    }
-
-    /**
-     * Checks to see if there are any {@link PowerManager.WakeLock}s that
-     * {@link androidx.work.impl.background.systemalarm.SystemAlarmService} holds when all the
-     * pending commands have been drained in the command queue.
-     */
-    public static void checkWakeLocks() {
-        // There is a small chance that while we are checking if all the commands in the queue are
-        // drained and wake locks are no longer being held, a new command comes along and we end up
-        // with a ConcurrentModificationException. The addition of commands happens on the command
-        // processor thread and this check is done on the main thread.
-
-        Map<PowerManager.WakeLock, String> wakeLocksCopy = new HashMap<>();
-        synchronized (sWakeLocks) {
-            // Copy the WakeLocks - otherwise we can get a ConcurrentModificationException if the
-            // garbage collector kicks in and ends up removing something from the master copy while
-            // we are iterating over it.
-            wakeLocksCopy.putAll(sWakeLocks);
-        }
-
-        for (PowerManager.WakeLock wakeLock : wakeLocksCopy.keySet()) {
-            if (wakeLock != null && wakeLock.isHeld()) {
-                String message = "WakeLock held for " + wakeLocksCopy.get(wakeLock);
-                Logger.get().warning(TAG, message);
-            }
-        }
-    }
-
-    private WakeLocks() {
-    }
-}
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/utils/WakeLocks.kt b/work/work-runtime/src/main/java/androidx/work/impl/utils/WakeLocks.kt
new file mode 100644
index 0000000..169ccf1
--- /dev/null
+++ b/work/work-runtime/src/main/java/androidx/work/impl/utils/WakeLocks.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2018 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.
+ */
+@file:JvmName("WakeLocks")
+
+package androidx.work.impl.utils
+
+import android.content.Context
+import android.os.PowerManager
+import androidx.work.Logger
+import java.util.WeakHashMap
+
+private val TAG = Logger.tagWithPrefix("WakeLocks")
+
+/**
+ * Creates and returns a new WakeLock.
+ *
+ * @param context The context from which to get the PowerManager
+ * @param tag A descriptive tag for the WakeLock; this method will prefix "WorkManager: " to it
+ * @return A new [android.os.PowerManager.WakeLock]
+ */
+internal fun newWakeLock(context: Context, tag: String): PowerManager.WakeLock {
+    val powerManager = context.applicationContext
+        .getSystemService(Context.POWER_SERVICE) as PowerManager
+    val tagWithPrefix = "WorkManager: $tag"
+    val wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, tagWithPrefix)
+    // Wakelocks are created on the command processor thread, but we check if they are still
+    // being held on the main thread.
+    synchronized(WakeLocksHolder) {
+        WakeLocksHolder.wakeLocks.put(wakeLock, tagWithPrefix)
+    }
+    return wakeLock
+}
+
+/**
+ * Checks to see if there are any [PowerManager.WakeLock]s that
+ * [androidx.work.impl.background.systemalarm.SystemAlarmService] holds when all the
+ * pending commands have been drained in the command queue.
+ */
+fun checkWakeLocks() {
+    // There is a small chance that while we are checking if all the commands in the queue are
+    // drained and wake locks are no longer being held, a new command comes along and we end up
+    // with a ConcurrentModificationException. The addition of commands happens on the command
+    // processor thread and this check is done on the main thread.
+    val wakeLocksCopy = mutableMapOf<PowerManager.WakeLock?, String>()
+    synchronized(WakeLocksHolder) {
+        // Copy the WakeLocks - otherwise we can get a ConcurrentModificationException if the
+        // garbage collector kicks in and ends up removing something from the master copy while
+        // we are iterating over it.
+        wakeLocksCopy.putAll(WakeLocksHolder.wakeLocks)
+    }
+
+    wakeLocksCopy.forEach { (wakeLock, tag) ->
+        if (wakeLock?.isHeld == true) Logger.get().warning(TAG, "WakeLock held for $tag")
+    }
+}
+
+private object WakeLocksHolder {
+    val wakeLocks = WeakHashMap<PowerManager.WakeLock, String>()
+}
\ No newline at end of file
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/workers/CombineContinuationsWorker.java b/work/work-runtime/src/main/java/androidx/work/impl/workers/CombineContinuationsWorker.java
deleted file mode 100644
index ef29c98..0000000
--- a/work/work-runtime/src/main/java/androidx/work/impl/workers/CombineContinuationsWorker.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2018 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.impl.workers;
-
-import android.content.Context;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.work.Worker;
-import androidx.work.WorkerParameters;
-
-/**
- * A {@link Worker} that helps combine work continuations.
- *
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class CombineContinuationsWorker extends Worker {
-
-    public CombineContinuationsWorker(@NonNull Context context,
-            @NonNull WorkerParameters workerParams) {
-        super(context, workerParams);
-    }
-
-    @Override
-    public @NonNull Result doWork() {
-        return Result.success(getInputData());
-    }
-}
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/workers/CombineContinuationsWorker.kt b/work/work-runtime/src/main/java/androidx/work/impl/workers/CombineContinuationsWorker.kt
new file mode 100644
index 0000000..484da27
--- /dev/null
+++ b/work/work-runtime/src/main/java/androidx/work/impl/workers/CombineContinuationsWorker.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018 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.impl.workers
+
+import android.content.Context
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+
+/**
+ * A [Worker] that helps combine work continuations.
+ */
+internal class CombineContinuationsWorker(
+    context: Context,
+    workerParams: WorkerParameters
+) : Worker(context, workerParams) {
+    override fun doWork() = Result.success(inputData)
+}
\ No newline at end of file
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/workers/ConstraintTrackingWorker.java b/work/work-runtime/src/main/java/androidx/work/impl/workers/ConstraintTrackingWorker.java
deleted file mode 100644
index 10c3d99..0000000
--- a/work/work-runtime/src/main/java/androidx/work/impl/workers/ConstraintTrackingWorker.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright 2018 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.impl.workers;
-
-import android.content.Context;
-import android.text.TextUtils;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
-import androidx.annotation.VisibleForTesting;
-import androidx.work.ListenableWorker;
-import androidx.work.Logger;
-import androidx.work.Worker;
-import androidx.work.WorkerParameters;
-import androidx.work.impl.WorkDatabase;
-import androidx.work.impl.WorkManagerImpl;
-import androidx.work.impl.constraints.WorkConstraintsCallback;
-import androidx.work.impl.constraints.WorkConstraintsTrackerImpl;
-import androidx.work.impl.constraints.trackers.Trackers;
-import androidx.work.impl.model.WorkSpec;
-import androidx.work.impl.utils.futures.SettableFuture;
-import androidx.work.impl.utils.taskexecutor.TaskExecutor;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Is an implementation of a {@link Worker} that can delegate to a different {@link Worker}
- * when the constraints are met.
- *
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class ConstraintTrackingWorker extends ListenableWorker implements WorkConstraintsCallback {
-
-    private static final String TAG = Logger.tagWithPrefix("ConstraintTrkngWrkr");
-
-    /**
-     * The {@code className} of the {@link Worker} to delegate to.
-     */
-    public static final String ARGUMENT_CLASS_NAME =
-            "androidx.work.impl.workers.ConstraintTrackingWorker.ARGUMENT_CLASS_NAME";
-
-    private WorkerParameters mWorkerParameters;
-
-    // These are package-private to avoid synthetic accessor.
-    final Object mLock;
-    // Marking this volatile as the delegated workers could switch threads.
-    volatile boolean mAreConstraintsUnmet;
-    SettableFuture<Result> mFuture;
-
-    @Nullable private ListenableWorker mDelegate;
-
-    public ConstraintTrackingWorker(@NonNull Context appContext,
-            @NonNull WorkerParameters workerParams) {
-        super(appContext, workerParams);
-        mWorkerParameters = workerParams;
-        mLock = new Object();
-        mAreConstraintsUnmet = false;
-        mFuture = SettableFuture.create();
-    }
-
-    @NonNull
-    @Override
-    public ListenableFuture<Result> startWork() {
-        getBackgroundExecutor().execute(new Runnable() {
-            @Override
-            public void run() {
-                setupAndRunConstraintTrackingWork();
-            }
-        });
-        return mFuture;
-    }
-
-    // Package-private to avoid synthetic accessor.
-    void setupAndRunConstraintTrackingWork() {
-        String className = getInputData().getString(ARGUMENT_CLASS_NAME);
-        if (TextUtils.isEmpty(className)) {
-            Logger.get().error(TAG, "No worker to delegate to.");
-            setFutureFailed();
-            return;
-        }
-
-        mDelegate = getWorkerFactory().createWorkerWithDefaultFallback(
-                getApplicationContext(),
-                className,
-                mWorkerParameters);
-
-        if (mDelegate == null) {
-            Logger.get().debug(TAG, "No worker to delegate to.");
-            setFutureFailed();
-            return;
-        }
-
-        WorkDatabase workDatabase = getWorkDatabase();
-
-        // We need to know what the real constraints are for the delegate.
-        WorkSpec workSpec = workDatabase.workSpecDao().getWorkSpec(getId().toString());
-        if (workSpec == null) {
-            setFutureFailed();
-            return;
-        }
-        WorkConstraintsTrackerImpl workConstraintsTracker =
-                new WorkConstraintsTrackerImpl(getTrackers(), this);
-
-        // Start tracking
-        workConstraintsTracker.replace(Collections.singletonList(workSpec));
-
-        if (workConstraintsTracker.areAllConstraintsMet(getId().toString())) {
-            Logger.get().debug(TAG, "Constraints met for delegate " + className);
-
-            // Wrapping the call to mDelegate#doWork() in a try catch, because
-            // changes in constraints can cause the worker to throw RuntimeExceptions, and
-            // that should cause a retry.
-            try {
-                final ListenableFuture<Result> innerFuture = mDelegate.startWork();
-                innerFuture.addListener(new Runnable() {
-                    @Override
-                    public void run() {
-                        synchronized (mLock) {
-                            if (mAreConstraintsUnmet) {
-                                setFutureRetry();
-                            } else {
-                                mFuture.setFuture(innerFuture);
-                            }
-                        }
-                    }
-                }, getBackgroundExecutor());
-            } catch (Throwable exception) {
-                Logger.get().debug(TAG, String.format(
-                        "Delegated worker %s threw exception in startWork.", className),
-                        exception);
-                synchronized (mLock) {
-                    if (mAreConstraintsUnmet) {
-                        Logger.get().debug(TAG, "Constraints were unmet, Retrying.");
-                        setFutureRetry();
-                    } else {
-                        setFutureFailed();
-                    }
-                }
-            }
-        } else {
-            Logger.get().debug(TAG, String.format(
-                    "Constraints not met for delegate %s. Requesting retry.", className));
-            setFutureRetry();
-        }
-
-    }
-
-    // Package-private to avoid synthetic accessor.
-    void setFutureFailed() {
-        mFuture.set(Result.failure());
-    }
-
-    // Package-private to avoid synthetic accessor.
-    void setFutureRetry() {
-        mFuture.set(Result.retry());
-    }
-
-    @Override
-    public void onStopped() {
-        super.onStopped();
-        if (mDelegate != null && !mDelegate.isStopped()) {
-            // Stop is the method that sets the stopped and cancelled bits and invokes onStopped.
-            mDelegate.stop();
-        }
-    }
-
-    /**
-     * @return The instance of {@link WorkDatabase}
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    @VisibleForTesting
-    @NonNull
-    public WorkDatabase getWorkDatabase() {
-        return WorkManagerImpl.getInstance(getApplicationContext()).getWorkDatabase();
-    }
-
-    /**
-     * @return The instance of {@link TaskExecutor}.
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    @VisibleForTesting
-    @NonNull
-    @Override
-    public TaskExecutor getTaskExecutor() {
-        return WorkManagerImpl.getInstance(getApplicationContext()).getWorkTaskExecutor();
-    }
-
-    /**
-     * @return The instance of {@link Trackers}.
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    @VisibleForTesting
-    @NonNull
-    public Trackers getTrackers() {
-        return WorkManagerImpl.getInstance(getApplicationContext()).getTrackers();
-    }
-
-    /**
-     * @return The {@link Worker} used for delegated work
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    @VisibleForTesting
-    @Nullable
-    public ListenableWorker getDelegate() {
-        return mDelegate;
-    }
-
-    @Override
-    public void onAllConstraintsMet(@NonNull List<String> workSpecIds) {
-        // WorkConstraintTracker notifies on the main thread. So we don't want to trampoline
-        // between the background thread and the main thread in this case.
-    }
-
-    @Override
-    public void onAllConstraintsNotMet(@NonNull List<String> workSpecIds) {
-        // If at any point, constraints are not met mark it so we can retry the work.
-        Logger.get().debug(TAG, "Constraints changed for " + workSpecIds);
-        synchronized (mLock) {
-            mAreConstraintsUnmet = true;
-        }
-    }
-}
\ No newline at end of file
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/workers/ConstraintTrackingWorker.kt b/work/work-runtime/src/main/java/androidx/work/impl/workers/ConstraintTrackingWorker.kt
new file mode 100644
index 0000000..788346c
--- /dev/null
+++ b/work/work-runtime/src/main/java/androidx/work/impl/workers/ConstraintTrackingWorker.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2018 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.impl.workers
+
+import android.content.Context
+import androidx.annotation.RestrictTo
+import androidx.annotation.VisibleForTesting
+import androidx.work.ListenableWorker
+import androidx.work.ListenableWorker.Result
+import androidx.work.Logger
+import androidx.work.WorkerParameters
+import androidx.work.impl.WorkManagerImpl
+import androidx.work.impl.constraints.WorkConstraintsCallback
+import androidx.work.impl.constraints.WorkConstraintsTrackerImpl
+import androidx.work.impl.utils.futures.SettableFuture
+import com.google.common.util.concurrent.ListenableFuture
+
+/**
+ * Is an implementation of a [androidx.work.Worker] that can delegate to a different
+ * [androidx.work.Worker] when the constraints are met.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class ConstraintTrackingWorker(
+    appContext: Context,
+    private val workerParameters: WorkerParameters
+) : ListenableWorker(appContext, workerParameters), WorkConstraintsCallback {
+
+    private val lock = Any()
+
+    // Marking this volatile as the delegated workers could switch threads.
+    @Volatile
+    private var areConstraintsUnmet: Boolean = false
+    private val future = SettableFuture.create<Result>()
+
+    /**
+     * @return The [androidx.work.Worker] used for delegated work
+     * @hide
+     */
+    @get:VisibleForTesting
+    @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    var delegate: ListenableWorker? = null
+        private set
+
+    override fun startWork(): ListenableFuture<Result> {
+        backgroundExecutor.execute { setupAndRunConstraintTrackingWork() }
+        return future
+    }
+
+    private fun setupAndRunConstraintTrackingWork() {
+        if (future.isCancelled) return
+
+        val className = inputData.getString(ARGUMENT_CLASS_NAME)
+        val logger = Logger.get()
+        if (className.isNullOrEmpty()) {
+            logger.error(TAG, "No worker to delegate to.")
+            future.setFailed()
+            return
+        }
+        delegate = workerFactory.createWorkerWithDefaultFallback(
+            applicationContext, className, workerParameters
+        )
+        if (delegate == null) {
+            logger.debug(TAG, "No worker to delegate to.")
+            future.setFailed()
+            return
+        }
+
+        val workManagerImpl = WorkManagerImpl.getInstance(applicationContext)
+        // We need to know what the real constraints are for the delegate.
+        val workSpec = workManagerImpl.workDatabase.workSpecDao().getWorkSpec(id.toString())
+        if (workSpec == null) {
+            future.setFailed()
+            return
+        }
+        val workConstraintsTracker = WorkConstraintsTrackerImpl(workManagerImpl.trackers, this)
+
+        // Start tracking
+        workConstraintsTracker.replace(listOf(workSpec))
+        if (workConstraintsTracker.areAllConstraintsMet(id.toString())) {
+            logger.debug(TAG, "Constraints met for delegate $className")
+
+            // Wrapping the call to mDelegate#doWork() in a try catch, because
+            // changes in constraints can cause the worker to throw RuntimeExceptions, and
+            // that should cause a retry.
+            try {
+                val innerFuture = delegate!!.startWork()
+                innerFuture.addListener({
+                    synchronized(lock) {
+                        if (areConstraintsUnmet) {
+                            future.setRetry()
+                        } else {
+                            future.setFuture(innerFuture)
+                        }
+                    }
+                }, backgroundExecutor)
+            } catch (exception: Throwable) {
+                logger.debug(
+                    TAG, "Delegated worker $className threw exception in startWork.", exception
+                )
+                synchronized(lock) {
+                    if (areConstraintsUnmet) {
+                        logger.debug(TAG, "Constraints were unmet, Retrying.")
+                        future.setRetry()
+                    } else {
+                        future.setFailed()
+                    }
+                }
+            }
+        } else {
+            logger.debug(
+                TAG, "Constraints not met for delegate $className. Requesting retry."
+            )
+            future.setRetry()
+        }
+    }
+
+    override fun onStopped() {
+        super.onStopped()
+        val delegateInner = delegate
+        if (delegateInner != null && !delegateInner.isStopped) {
+            // Stop is the method that sets the stopped and cancelled bits and invokes onStopped.
+            delegateInner.stop()
+        }
+    }
+
+    override fun onAllConstraintsMet(workSpecIds: List<String>) {
+        // WorkConstraintTracker notifies on the main thread. So we don't want to trampoline
+        // between the background thread and the main thread in this case.
+    }
+
+    override fun onAllConstraintsNotMet(workSpecIds: List<String>) {
+        // If at any point, constraints are not met mark it so we can retry the work.
+        Logger.get().debug(TAG, "Constraints changed for $workSpecIds")
+        synchronized(lock) { areConstraintsUnmet = true }
+    }
+}
+
+private fun SettableFuture<Result>.setFailed() = set(Result.failure())
+private fun SettableFuture<Result>.setRetry() = set(Result.retry())
+
+private val TAG = Logger.tagWithPrefix("ConstraintTrkngWrkr")
+
+/**
+ * The `className` of the [androidx.work.Worker] to delegate to.
+ */
+internal const val ARGUMENT_CLASS_NAME =
+    "androidx.work.impl.workers.ConstraintTrackingWorker.ARGUMENT_CLASS_NAME"
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/workers/DiagnosticsWorker.java b/work/work-runtime/src/main/java/androidx/work/impl/workers/DiagnosticsWorker.java
deleted file mode 100644
index 3f20289..0000000
--- a/work/work-runtime/src/main/java/androidx/work/impl/workers/DiagnosticsWorker.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2020 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.impl.workers;
-
-import static androidx.work.impl.Scheduler.MAX_GREEDY_SCHEDULER_LIMIT;
-
-import android.content.Context;
-import android.os.Build;
-import android.text.TextUtils;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
-import androidx.work.Logger;
-import androidx.work.Worker;
-import androidx.work.WorkerParameters;
-import androidx.work.impl.WorkDatabase;
-import androidx.work.impl.WorkManagerImpl;
-import androidx.work.impl.model.SystemIdInfo;
-import androidx.work.impl.model.SystemIdInfoDao;
-import androidx.work.impl.model.WorkNameDao;
-import androidx.work.impl.model.WorkSpec;
-import androidx.work.impl.model.WorkSpecDao;
-import androidx.work.impl.model.WorkTagDao;
-
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-/**
- * The {@link androidx.work.Worker} which dumps diagnostic information.
- *
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class DiagnosticsWorker extends Worker {
-
-    private static final String TAG = Logger.tagWithPrefix("DiagnosticsWrkr");
-
-    public DiagnosticsWorker(@NonNull Context context, @NonNull WorkerParameters parameters) {
-        super(context, parameters);
-    }
-
-    @NonNull
-    @Override
-    public Result doWork() {
-        WorkManagerImpl workManager = WorkManagerImpl.getInstance(getApplicationContext());
-        WorkDatabase database = workManager.getWorkDatabase();
-        WorkSpecDao workSpecDao = database.workSpecDao();
-        WorkNameDao workNameDao = database.workNameDao();
-        WorkTagDao workTagDao = database.workTagDao();
-        SystemIdInfoDao systemIdInfoDao = database.systemIdInfoDao();
-        long startAt = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1);
-        List<WorkSpec> completed = workSpecDao.getRecentlyCompletedWork(startAt);
-        List<WorkSpec> running = workSpecDao.getRunningWork();
-        List<WorkSpec> enqueued = workSpecDao.getAllEligibleWorkSpecsForScheduling(
-                MAX_GREEDY_SCHEDULER_LIMIT);
-
-        if (completed != null && !completed.isEmpty()) {
-            Logger.get().info(TAG, "Recently completed work:\n\n");
-            Logger.get().info(TAG,
-                    workSpecRows(workNameDao, workTagDao, systemIdInfoDao, completed));
-        }
-        if (running != null && !running.isEmpty()) {
-            Logger.get().info(TAG, "Running work:\n\n");
-            Logger.get().info(TAG, workSpecRows(workNameDao, workTagDao, systemIdInfoDao, running));
-        }
-        if (enqueued != null && !enqueued.isEmpty()) {
-            Logger.get().info(TAG, "Enqueued work:\n\n");
-            Logger.get().info(TAG,
-                    workSpecRows(workNameDao, workTagDao, systemIdInfoDao, enqueued));
-        }
-        return Result.success();
-    }
-
-    @NonNull
-    private static String workSpecRows(
-            @NonNull WorkNameDao workNameDao,
-            @NonNull WorkTagDao workTagDao,
-            @NonNull SystemIdInfoDao systemIdInfoDao,
-            @NonNull List<WorkSpec> workSpecs) {
-
-        StringBuilder sb = new StringBuilder();
-        String systemIdHeader = Build.VERSION.SDK_INT >= 23 ? "Job Id" : "Alarm Id";
-        String header = String.format("\n Id \t Class Name\t %s\t State\t Unique Name\t Tags\t",
-                systemIdHeader);
-        sb.append(header);
-        for (WorkSpec workSpec : workSpecs) {
-            Integer systemId = null;
-            SystemIdInfo info = systemIdInfoDao.getSystemIdInfo(workSpec.id);
-            if (info != null) {
-                systemId = info.systemId;
-            }
-            List<String> names = workNameDao.getNamesForWorkSpecId(workSpec.id);
-            List<String> tags = workTagDao.getTagsForWorkSpecId(workSpec.id);
-            sb.append(workSpecRow(
-                    workSpec,
-                    TextUtils.join(",", names),
-                    systemId,
-                    TextUtils.join(",", tags)
-            ));
-        }
-        return sb.toString();
-    }
-
-    @NonNull
-    private static String workSpecRow(
-            @NonNull WorkSpec workSpec,
-            @Nullable String name,
-            @Nullable Integer systemId,
-            @NonNull String tags) {
-        return String.format(
-                "\n%s\t %s\t %s\t %s\t %s\t %s\t",
-                workSpec.id,
-                workSpec.workerClassName,
-                systemId,
-                workSpec.state.name(),
-                name,
-                tags);
-    }
-}
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/workers/DiagnosticsWorker.kt b/work/work-runtime/src/main/java/androidx/work/impl/workers/DiagnosticsWorker.kt
new file mode 100644
index 0000000..7755b70
--- /dev/null
+++ b/work/work-runtime/src/main/java/androidx/work/impl/workers/DiagnosticsWorker.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020 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.impl.workers
+
+import android.content.Context
+import android.os.Build
+import androidx.work.Logger
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import androidx.work.impl.Scheduler
+import androidx.work.impl.WorkManagerImpl
+import androidx.work.impl.model.SystemIdInfoDao
+import androidx.work.impl.model.WorkNameDao
+import androidx.work.impl.model.WorkSpec
+import androidx.work.impl.model.WorkTagDao
+import java.util.concurrent.TimeUnit
+
+internal class DiagnosticsWorker(context: Context, parameters: WorkerParameters) :
+    Worker(context, parameters) {
+    override fun doWork(): Result {
+        val workManager = WorkManagerImpl.getInstance(applicationContext)
+        val database = workManager.workDatabase
+        val workSpecDao = database.workSpecDao()
+        val workNameDao = database.workNameDao()
+        val workTagDao = database.workTagDao()
+        val systemIdInfoDao = database.systemIdInfoDao()
+        val startAt = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1)
+        val completed = workSpecDao.getRecentlyCompletedWork(startAt)
+        val running = workSpecDao.getRunningWork()
+        val enqueued = workSpecDao.getAllEligibleWorkSpecsForScheduling(
+            Scheduler.MAX_GREEDY_SCHEDULER_LIMIT
+        )
+        if (completed.isNotEmpty()) {
+            Logger.get().info(TAG, "Recently completed work:\n\n")
+            Logger.get().info(
+                TAG, workSpecRows(workNameDao, workTagDao, systemIdInfoDao, completed)
+            )
+        }
+        if (running.isNotEmpty()) {
+            Logger.get().info(TAG, "Running work:\n\n")
+            Logger.get().info(TAG, workSpecRows(workNameDao, workTagDao, systemIdInfoDao, running))
+        }
+        if (enqueued.isNotEmpty()) {
+            Logger.get().info(TAG, "Enqueued work:\n\n")
+            Logger.get().info(TAG, workSpecRows(workNameDao, workTagDao, systemIdInfoDao, enqueued))
+        }
+        return Result.success()
+    }
+}
+
+private val TAG = Logger.tagWithPrefix("DiagnosticsWrkr")
+
+private fun workSpecRows(
+    workNameDao: WorkNameDao,
+    workTagDao: WorkTagDao,
+    systemIdInfoDao: SystemIdInfoDao,
+    workSpecs: List<WorkSpec>
+) = buildString {
+    val systemIdHeader = if (Build.VERSION.SDK_INT >= 23) "Job Id" else "Alarm Id"
+    val header = "\n Id \t Class Name\t ${systemIdHeader}\t State\t Unique Name\t Tags\t"
+    append(header)
+    workSpecs.forEach { workSpec ->
+        val systemId = systemIdInfoDao.getSystemIdInfo(workSpec.id)?.systemId
+        val names = workNameDao.getNamesForWorkSpecId(workSpec.id).joinToString(",")
+        val tags = workTagDao.getTagsForWorkSpecId(workSpec.id).joinToString(",")
+        append(workSpecRow(workSpec, names, systemId, tags))
+    }
+}
+
+private fun workSpecRow(workSpec: WorkSpec, name: String, systemId: Int?, tags: String) =
+    "\n${workSpec.id}\t ${workSpec.workerClassName}\t $systemId\t " +
+        "${workSpec.state.name}\t $name\t $tags\t"