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"