Make it simpler to delegate to instances of RemoteListenableDelegatingWorker.
* The API makes it possible to delegate to the default WorkerFactory when creating instances of RemoteListenableDelegatingWorker.
* This way you can move a `RemoteListenableWorker` from the main process to a remote process transparently, and even switch processes subsequently.
Test: Updated RemoteCoroutineWorkerTest.
Bug: 343527722
Relnote: Make it simpler to delegate to instances of `RemoteListenableDelegatingWorker`.
Change-Id: I7373f2fa1db38f5649cb6091bb69d58999b2ddba
diff --git a/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteCoroutineWorkerTest.kt b/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteCoroutineWorkerTest.kt
index aeb720f..60fed73 100644
--- a/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteCoroutineWorkerTest.kt
+++ b/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteCoroutineWorkerTest.kt
@@ -28,6 +28,7 @@
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkInfo
import androidx.work.WorkRequest
+import androidx.work.buildDelegatedRemoteRequestData
import androidx.work.impl.Processor
import androidx.work.impl.Scheduler
import androidx.work.impl.WorkDatabase
@@ -38,7 +39,6 @@
import androidx.work.impl.utils.taskexecutor.TaskExecutor
import androidx.work.isRemoteWorkRequest
import androidx.work.multiprocess.RemoteListenableDelegatingWorker.Companion.ARGUMENT_REMOTE_LISTENABLE_WORKER_NAME
-import androidx.work.usingRemoteService
import java.util.concurrent.Executor
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -163,13 +163,25 @@
return
}
- val request = buildRequest<RemoteSuccessWorker>()
val packageName = "PACKAGE_NAME"
val className = "CLASS_NAME"
- val data = request.workSpec.input.usingRemoteService(ComponentName(packageName, className))
+ val inputKey = "INPUT_KEY"
+ val inputValue = "InputValue"
+ val inputData = Data.Builder().putString(inputKey, inputValue).build()
+ val data =
+ buildDelegatedRemoteRequestData(
+ delegatedWorkerName = RemoteSuccessWorker::class.java.name,
+ componentName = ComponentName(packageName, className),
+ inputData
+ )
assertEquals(data.isRemoteWorkRequest(), true)
+ assertEquals(
+ data.getString(ARGUMENT_REMOTE_LISTENABLE_WORKER_NAME),
+ RemoteSuccessWorker::class.java.name
+ )
assertEquals(data.getString(RemoteListenableWorker.ARGUMENT_PACKAGE_NAME), packageName)
assertEquals(data.getString(RemoteListenableWorker.ARGUMENT_CLASS_NAME), className)
+ assertEquals(data.getString(inputKey), inputValue)
}
private inline fun <reified T : ListenableWorker> buildRequest(): OneTimeWorkRequest {
diff --git a/work/work-runtime/api/current.txt b/work/work-runtime/api/current.txt
index 0b5be26..5cd8014 100644
--- a/work/work-runtime/api/current.txt
+++ b/work/work-runtime/api/current.txt
@@ -636,7 +636,8 @@
public final class WorkerParametersExtensions {
method public static boolean isRemoteWorkRequest(androidx.work.WorkerParameters);
- method public static androidx.work.WorkerParameters usingRemoteService(androidx.work.WorkerParameters, android.content.ComponentName componentName);
+ method public static inline <reified T extends androidx.work.ListenableWorker> androidx.work.WorkerParameters usingRemoteService(androidx.work.WorkerParameters, android.content.ComponentName componentName);
+ method public static androidx.work.WorkerParameters usingRemoteService(androidx.work.WorkerParameters, String workerClassName, android.content.ComponentName componentName);
}
}
diff --git a/work/work-runtime/api/restricted_current.txt b/work/work-runtime/api/restricted_current.txt
index 0b5be26..5cd8014 100644
--- a/work/work-runtime/api/restricted_current.txt
+++ b/work/work-runtime/api/restricted_current.txt
@@ -636,7 +636,8 @@
public final class WorkerParametersExtensions {
method public static boolean isRemoteWorkRequest(androidx.work.WorkerParameters);
- method public static androidx.work.WorkerParameters usingRemoteService(androidx.work.WorkerParameters, android.content.ComponentName componentName);
+ method public static inline <reified T extends androidx.work.ListenableWorker> androidx.work.WorkerParameters usingRemoteService(androidx.work.WorkerParameters, android.content.ComponentName componentName);
+ method public static androidx.work.WorkerParameters usingRemoteService(androidx.work.WorkerParameters, String workerClassName, android.content.ComponentName componentName);
}
}
diff --git a/work/work-runtime/src/main/java/androidx/work/WorkerParameters.kt b/work/work-runtime/src/main/java/androidx/work/WorkerParameters.kt
index 064e029..4814646 100644
--- a/work/work-runtime/src/main/java/androidx/work/WorkerParameters.kt
+++ b/work/work-runtime/src/main/java/androidx/work/WorkerParameters.kt
@@ -36,14 +36,33 @@
* Returns a new instance of [WorkerParameters] representing a [WorkRequest] that can run in a
* process corresponding to the provided [ComponentName].
*
+ * @param T The [ListenableWorker] to delegate to.
* @param componentName The [ComponentName] that identifies the `RemoteService` that hosts the
* [WorkRequest].
* @return A new instance of [WorkerParameters]
*/
-fun WorkerParameters.usingRemoteService(componentName: ComponentName): WorkerParameters {
+inline fun <reified T : ListenableWorker> WorkerParameters.usingRemoteService(
+ componentName: ComponentName
+): WorkerParameters {
+ return usingRemoteService(T::class.java.name, componentName)
+}
+
+/**
+ * Returns a new instance of [WorkerParameters] representing a [WorkRequest] that can run in a
+ * process corresponding to the provided [ComponentName].
+ *
+ * @param workerClassName The fully qualified class name of the [ListenableWorker] to delegate to
+ * @param componentName The [ComponentName] that identifies the `RemoteService` that hosts the
+ * [WorkRequest].
+ * @return A new instance of [WorkerParameters]
+ */
+fun WorkerParameters.usingRemoteService(
+ workerClassName: String,
+ componentName: ComponentName
+): WorkerParameters {
return WorkerParameters(
id,
- inputData.usingRemoteService(componentName),
+ buildDelegatedRemoteRequestData(workerClassName, componentName, inputData),
tags,
runtimeExtras,
runAttemptCount,
@@ -58,23 +77,23 @@
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-fun Data.isRemoteWorkRequest(): Boolean {
- return hasKey<String>(ARGUMENT_REMOTE_LISTENABLE_WORKER_NAME)
+fun buildDelegatedRemoteRequestData(
+ delegatedWorkerName: String,
+ componentName: ComponentName,
+ inputData: Data
+): Data {
+ val builder = Data.Builder()
+ builder
+ .putAll(data = inputData)
+ .putString(ARGUMENT_SERVICE_PACKAGE_NAME, componentName.packageName)
+ .putString(ARGUMENT_SERVICE_CLASS_NAME, componentName.className)
+ .putString(ARGUMENT_REMOTE_LISTENABLE_WORKER_NAME, delegatedWorkerName)
+ return builder.build()
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-fun Data.usingRemoteService(componentName: ComponentName): Data {
- val hasPackageName = hasKey<String>(ARGUMENT_SERVICE_PACKAGE_NAME)
- val hasClassName = hasKey<String>(ARGUMENT_SERVICE_CLASS_NAME)
- require(hasPackageName && hasClassName) {
- "$this does not correspond to a request for work in a remote process."
- }
- val data =
- Data.Builder()
- .putAll(this)
- .putString(ARGUMENT_SERVICE_PACKAGE_NAME, componentName.packageName)
- .putString(ARGUMENT_SERVICE_CLASS_NAME, componentName.className)
- .build()
-
- return data
+fun Data.isRemoteWorkRequest(): Boolean {
+ return hasKey<String>(ARGUMENT_SERVICE_PACKAGE_NAME) &&
+ hasKey<String>(ARGUMENT_SERVICE_CLASS_NAME) &&
+ hasKey<String>(ARGUMENT_REMOTE_LISTENABLE_WORKER_NAME)
}
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/utils/EnqueueUtils.kt b/work/work-runtime/src/main/java/androidx/work/impl/utils/EnqueueUtils.kt
index c2f1d2d..47d8d5a 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/utils/EnqueueUtils.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/utils/EnqueueUtils.kt
@@ -142,11 +142,6 @@
}
}
-// The name of the worker to delegate to when it's a Remote Listenable Worker
-
-internal const val REMOTE_DELEGATING_LISTENABLE_WORKER_CLASS_NAME =
- "androidx.work.multiprocess.RemoteListenableDelegatingWorker"
-
// Redefine the keys
internal const val ARGUMENT_SERVICE_PACKAGE_NAME =
@@ -155,6 +150,16 @@
internal const val ARGUMENT_SERVICE_CLASS_NAME =
"androidx.work.impl.workers.RemoteListenableWorker.ARGUMENT_CLASS_NAME"
+/**
+ * Originally defined in `RemoteListenableDelegatingWorker.kt`. This method is being re-defined here
+ * to avoid a circular dependency on the multiprocess library.
+ *
+ * The fully qualified name of the class that is used when running in the context of a remote
+ * process. This constant is useful when migrating remote workers between processes.
+ */
+internal const val REMOTE_DELEGATING_LISTENABLE_WORKER_CLASS_NAME =
+ "androidx.work.multiprocess.RemoteListenableDelegatingWorker"
+
// The RemoteListenableWorker class to delegate to.
internal const val ARGUMENT_REMOTE_LISTENABLE_WORKER_NAME =