Merge "RxJava3: RxJava wrapper around getForegroundInfoAsync" into androidx-main
diff --git a/work/work-rxjava2/src/test/java/androidx/work/RxForegroundInfoTest.kt b/work/work-rxjava2/src/test/java/androidx/work/RxForegroundInfoTest.kt
new file mode 100644
index 0000000..b901812
--- /dev/null
+++ b/work/work-rxjava2/src/test/java/androidx/work/RxForegroundInfoTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.work
+
+import android.content.Context
+import androidx.work.impl.utils.SynchronousExecutor
+import io.reactivex.Single
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito.mock
+import java.util.UUID
+import java.util.concurrent.Executor
+
+@RunWith(JUnit4::class)
+class SingleForegroundInfoTest {
+
+ @Test
+ fun foo() {
+ val context = mock(Context::class.java)
+ TestRxWorker(context, createWorkerParams())
+ }
+
+ private fun createWorkerParams(
+ executor: Executor = SynchronousExecutor(),
+ progressUpdater: ProgressUpdater = mock(ProgressUpdater::class.java),
+ foregroundUpdater: ForegroundUpdater = mock(ForegroundUpdater::class.java)
+ ) = WorkerParameters(
+ UUID.randomUUID(),
+ Data.EMPTY,
+ emptyList(),
+ WorkerParameters.RuntimeExtras(),
+ 1,
+ executor,
+ RxWorkerTest.InstantWorkTaskExecutor(),
+ WorkerFactory.getDefaultWorkerFactory(),
+ progressUpdater,
+ foregroundUpdater
+ )
+}
+
+private class WorkerForeground(
+ appContext: Context,
+ workerParams: WorkerParameters
+) : RxWorker(appContext, workerParams) {
+ override fun createWork(): Single<Result> {
+ throw UnsupportedOperationException()
+ }
+}
\ No newline at end of file
diff --git a/work/work-rxjava3/api/current.txt b/work/work-rxjava3/api/current.txt
index 9293340..944514c 100644
--- a/work/work-rxjava3/api/current.txt
+++ b/work/work-rxjava3/api/current.txt
@@ -5,6 +5,7 @@
ctor public RxWorker(android.content.Context, androidx.work.WorkerParameters);
method @MainThread public abstract io.reactivex.rxjava3.core.Single<androidx.work.ListenableWorker.Result!> createWork();
method protected io.reactivex.rxjava3.core.Scheduler getBackgroundScheduler();
+ method public io.reactivex.rxjava3.core.Single<androidx.work.ForegroundInfo!> getForegroundInfo();
method public final io.reactivex.rxjava3.core.Completable setCompletableProgress(androidx.work.Data);
method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
}
diff --git a/work/work-rxjava3/api/public_plus_experimental_current.txt b/work/work-rxjava3/api/public_plus_experimental_current.txt
index 9293340..944514c 100644
--- a/work/work-rxjava3/api/public_plus_experimental_current.txt
+++ b/work/work-rxjava3/api/public_plus_experimental_current.txt
@@ -5,6 +5,7 @@
ctor public RxWorker(android.content.Context, androidx.work.WorkerParameters);
method @MainThread public abstract io.reactivex.rxjava3.core.Single<androidx.work.ListenableWorker.Result!> createWork();
method protected io.reactivex.rxjava3.core.Scheduler getBackgroundScheduler();
+ method public io.reactivex.rxjava3.core.Single<androidx.work.ForegroundInfo!> getForegroundInfo();
method public final io.reactivex.rxjava3.core.Completable setCompletableProgress(androidx.work.Data);
method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
}
diff --git a/work/work-rxjava3/api/restricted_current.txt b/work/work-rxjava3/api/restricted_current.txt
index 9293340..944514c 100644
--- a/work/work-rxjava3/api/restricted_current.txt
+++ b/work/work-rxjava3/api/restricted_current.txt
@@ -5,6 +5,7 @@
ctor public RxWorker(android.content.Context, androidx.work.WorkerParameters);
method @MainThread public abstract io.reactivex.rxjava3.core.Single<androidx.work.ListenableWorker.Result!> createWork();
method protected io.reactivex.rxjava3.core.Scheduler getBackgroundScheduler();
+ method public io.reactivex.rxjava3.core.Single<androidx.work.ForegroundInfo!> getForegroundInfo();
method public final io.reactivex.rxjava3.core.Completable setCompletableProgress(androidx.work.Data);
method public final com.google.common.util.concurrent.ListenableFuture<androidx.work.ListenableWorker.Result!> startWork();
}
diff --git a/work/work-rxjava3/build.gradle b/work/work-rxjava3/build.gradle
index 6be9b57..98f7df9 100644
--- a/work/work-rxjava3/build.gradle
+++ b/work/work-rxjava3/build.gradle
@@ -26,6 +26,7 @@
dependencies {
api(project(":work:work-runtime"))
api(libs.rxjava3)
+ testImplementation(libs.truth)
testImplementation(libs.junit)
testImplementation(libs.kotlinStdlib)
testImplementation(libs.mockitoCore)
diff --git a/work/work-rxjava3/src/main/java/androidx/work/rxjava3/RxWorker.java b/work/work-rxjava3/src/main/java/androidx/work/rxjava3/RxWorker.java
index 39b0435..5c34476 100644
--- a/work/work-rxjava3/src/main/java/androidx/work/rxjava3/RxWorker.java
+++ b/work/work-rxjava3/src/main/java/androidx/work/rxjava3/RxWorker.java
@@ -24,8 +24,11 @@
import androidx.annotation.Nullable;
import androidx.work.Configuration;
import androidx.work.Data;
+import androidx.work.ForegroundInfo;
import androidx.work.ListenableWorker;
+import androidx.work.OutOfQuotaPolicy;
import androidx.work.WorkManager;
+import androidx.work.WorkRequest;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import androidx.work.impl.utils.SynchronousExecutor;
@@ -77,17 +80,7 @@
@Override
public final ListenableFuture<Result> startWork() {
mSingleFutureObserverAdapter = new SingleFutureAdapter<>();
-
- final Scheduler scheduler = getBackgroundScheduler();
- createWork()
- .subscribeOn(scheduler)
- // observe on WM's private thread
- .observeOn(Schedulers.from(
- getTaskExecutor().getBackgroundExecutor(),
- /* interruptible */true,
- /* fair */true))
- .subscribe(mSingleFutureObserverAdapter);
- return mSingleFutureObserverAdapter.mFuture;
+ return convert(mSingleFutureObserverAdapter, createWork());
}
/**
@@ -151,6 +144,49 @@
}
}
+ @NonNull
+ @Override
+ public ListenableFuture<ForegroundInfo> getForegroundInfoAsync() {
+ return convert(new SingleFutureAdapter<>(), getForegroundInfo());
+ }
+
+ /**
+ * Return an {@code Single} with an instance of {@link ForegroundInfo} if the
+ * {@link WorkRequest} is
+ * important to the user. In this case, WorkManager provides a signal to the OS that the
+ * process should be kept alive while this work is executing.
+ * <p>
+ * Prior to Android S, WorkManager manages and runs a foreground service on your behalf to
+ * execute the WorkRequest, showing the notification provided in the {@link ForegroundInfo}.
+ * To update this notification subsequently, the application can use
+ * {@link android.app.NotificationManager}.
+ * <p>
+ * Starting in Android S and above, WorkManager manages this WorkRequest using an immediate job.
+ *
+ * @return A {@link Single} of {@link ForegroundInfo} instance if the WorkRequest
+ * is marked immediate. For more information look at
+ * {@link WorkRequest.Builder#setExpedited(OutOfQuotaPolicy)}.
+ */
+ @NonNull
+ public Single<ForegroundInfo> getForegroundInfo() {
+ String message =
+ "Expedited WorkRequests require a RxWorker to provide an implementation for"
+ + " `getForegroundInfo()`";
+ return Single.error(new IllegalStateException(message));
+ }
+
+ private <T> ListenableFuture<T> convert(SingleFutureAdapter<T> adapter, Single<T> single) {
+ final Scheduler scheduler = getBackgroundScheduler();
+ single.subscribeOn(scheduler)
+ // observe on WM's private thread
+ .observeOn(Schedulers.from(
+ getTaskExecutor().getBackgroundExecutor(),
+ /* interruptible */true,
+ /* fair */true))
+ .subscribe(adapter);
+ return adapter.mFuture;
+ }
+
/**
* An observer that can observe a single and provide it as a {@link ListenableWorker}.
*/
diff --git a/work/work-rxjava3/src/test/java/androidx/work/rxjava3/RxForegroundInfoTest.kt b/work/work-rxjava3/src/test/java/androidx/work/rxjava3/RxForegroundInfoTest.kt
new file mode 100644
index 0000000..8d2f33c
--- /dev/null
+++ b/work/work-rxjava3/src/test/java/androidx/work/rxjava3/RxForegroundInfoTest.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.work.rxjava3
+
+import android.app.Notification
+import android.content.Context
+import androidx.work.Data
+import androidx.work.ForegroundInfo
+import androidx.work.ForegroundUpdater
+import androidx.work.ProgressUpdater
+import androidx.work.WorkerFactory
+import androidx.work.WorkerParameters
+import androidx.work.impl.utils.SynchronousExecutor
+import com.google.common.truth.Truth
+import io.reactivex.rxjava3.core.Single
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito.mock
+import java.util.UUID
+import java.util.concurrent.Executor
+
+@RunWith(JUnit4::class)
+class RxForegroundInfoTest {
+ @Test
+ fun testForegroundInfo() {
+ val context = mock(Context::class.java)
+ val foregroundInfo = WorkerForeground(context, createWorkerParams())
+ .foregroundInfoAsync.get()
+ Truth.assertThat(foregroundInfo).isEqualTo(testForegroundInfo)
+ }
+}
+
+private val testForegroundInfo = ForegroundInfo(10, mock(Notification::class.java))
+
+private class WorkerForeground(
+ appContext: Context,
+ workerParams: WorkerParameters
+) : RxWorker(appContext, workerParams) {
+ override fun createWork(): Single<Result> {
+ throw UnsupportedOperationException()
+ }
+
+ override fun getForegroundInfo(): Single<ForegroundInfo> = Single.just(testForegroundInfo)
+}
+
+private fun createWorkerParams(
+ executor: Executor = SynchronousExecutor(),
+ progressUpdater: ProgressUpdater = mock(ProgressUpdater::class.java),
+ foregroundUpdater: ForegroundUpdater = mock(ForegroundUpdater::class.java)
+) = WorkerParameters(
+ UUID.randomUUID(),
+ Data.EMPTY,
+ emptyList(),
+ WorkerParameters.RuntimeExtras(),
+ 1,
+ executor,
+ RxWorkerTest.InstantWorkTaskExecutor(),
+ WorkerFactory.getDefaultWorkerFactory(),
+ progressUpdater,
+ foregroundUpdater
+)