Introduce `ProgressUpdater`.
* WorkProgressUpdater updates work progress on the task executor thread.
* Update version to 2.2.0-alpha01.
Test: Updated unit tests.
Change-Id: I28eb4fe182c708f838758155a122c59dd682a453
diff --git a/work/workmanager-ktx/src/androidTest/java/androidx/work/CoroutineWorkerTest.kt b/work/workmanager-ktx/src/androidTest/java/androidx/work/CoroutineWorkerTest.kt
index f20e6f0..6232be6 100644
--- a/work/workmanager-ktx/src/androidTest/java/androidx/work/CoroutineWorkerTest.kt
+++ b/work/workmanager-ktx/src/androidTest/java/androidx/work/CoroutineWorkerTest.kt
@@ -25,6 +25,7 @@
import androidx.test.filters.SmallTest
import androidx.work.impl.WorkDatabase
import androidx.work.impl.WorkManagerImpl
+import androidx.work.impl.utils.futures.SettableFuture
import androidx.work.impl.utils.taskexecutor.TaskExecutor
import kotlinx.coroutines.asCoroutineDispatcher
import org.hamcrest.CoreMatchers.`is`
@@ -45,6 +46,7 @@
private lateinit var configuration: Configuration
private lateinit var database: WorkDatabase
private lateinit var workManagerImpl: WorkManagerImpl
+ private lateinit var progressUpdater: ProgressUpdater
@Before
fun setUp() {
@@ -73,6 +75,12 @@
)
WorkManagerImpl.setDelegate(workManagerImpl)
database = workManagerImpl.workDatabase
+ // No op
+ progressUpdater = ProgressUpdater { _, _, _ ->
+ val future = SettableFuture.create<Void>()
+ future.set(null)
+ future
+ }
}
@After
@@ -95,7 +103,8 @@
1,
configuration.executor,
workManagerImpl.workTaskExecutor,
- workerFactory)) as SynchronousCoroutineWorker
+ workerFactory,
+ progressUpdater)) as SynchronousCoroutineWorker
assertThat(worker.job.isCompleted, `is`(false))
@@ -124,7 +133,8 @@
1,
configuration.executor,
workManagerImpl.workTaskExecutor,
- workerFactory)) as SynchronousCoroutineWorker
+ workerFactory,
+ progressUpdater)) as SynchronousCoroutineWorker
assertThat(worker.job.isCancelled, `is`(false))
worker.future.cancel(true)
diff --git a/work/workmanager-rxjava2/src/test/java/androidx/work/RxWorkerTest.kt b/work/workmanager-rxjava2/src/test/java/androidx/work/RxWorkerTest.kt
index 54c9f47..bf07147 100644
--- a/work/workmanager-rxjava2/src/test/java/androidx/work/RxWorkerTest.kt
+++ b/work/workmanager-rxjava2/src/test/java/androidx/work/RxWorkerTest.kt
@@ -27,7 +27,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.mockito.Mockito
+import org.mockito.Mockito.mock
import java.util.UUID
import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executor
@@ -105,7 +105,7 @@
it.run()
}
val params = createWorkerParams(executor)
- val worker = object : RxWorker(Mockito.mock(Context::class.java), params) {
+ val worker = object : RxWorker(mock(Context::class.java), params) {
override fun createWork() = Single.just(result)
override fun getBackgroundScheduler() = testScheduler
}
@@ -115,7 +115,8 @@
}
private fun createWorkerParams(
- executor: Executor = SynchronousExecutor()
+ executor: Executor = SynchronousExecutor(),
+ progressUpdater: ProgressUpdater = mock(ProgressUpdater::class.java)
) = WorkerParameters(
UUID.randomUUID(),
Data.EMPTY,
@@ -124,13 +125,14 @@
1,
executor,
InstantWorkTaskExecutor(),
- WorkerFactory.getDefaultWorkerFactory()
+ WorkerFactory.getDefaultWorkerFactory(),
+ progressUpdater
)
private fun Single<ListenableWorker.Result>.toWorker(
params: WorkerParameters = createWorkerParams()
): RxWorker {
- return object : RxWorker(Mockito.mock(Context::class.java), params) {
+ return object : RxWorker(mock(Context::class.java), params) {
override fun createWork() = this@toWorker
}
}
diff --git a/work/workmanager-testing/src/main/java/androidx/work/testing/TestListenableWorkerBuilder.java b/work/workmanager-testing/src/main/java/androidx/work/testing/TestListenableWorkerBuilder.java
index 501d81d..189d183 100644
--- a/work/workmanager-testing/src/main/java/androidx/work/testing/TestListenableWorkerBuilder.java
+++ b/work/workmanager-testing/src/main/java/androidx/work/testing/TestListenableWorkerBuilder.java
@@ -25,6 +25,7 @@
import androidx.annotation.RestrictTo;
import androidx.work.Data;
import androidx.work.ListenableWorker;
+import androidx.work.ProgressUpdater;
import androidx.work.WorkRequest;
import androidx.work.WorkerFactory;
import androidx.work.WorkerParameters;
@@ -56,6 +57,7 @@
private WorkerFactory mWorkerFactory;
private TaskExecutor mTaskExecutor;
private Executor mExecutor;
+ private ProgressUpdater mProgressUpdater;
TestListenableWorkerBuilder(@NonNull Context context, @NonNull Class<W> workerClass) {
mContext = context;
@@ -69,6 +71,7 @@
mWorkerFactory = WorkerFactory.getDefaultWorkerFactory();
mTaskExecutor = new InstantWorkTaskExecutor();
mExecutor = mTaskExecutor.getBackgroundExecutor();
+ mProgressUpdater = new TestProgressUpdater();
}
/**
@@ -160,6 +163,12 @@
return mExecutor;
}
+ @NonNull
+ @SuppressWarnings("KotlinPropertyAccess")
+ ProgressUpdater getProgressUpdater() {
+ return mProgressUpdater;
+ }
+
/**
* Sets the id for this unit of work.
*
@@ -263,6 +272,19 @@
}
/**
+ * Sets the {@link ProgressUpdater} to be used to construct the
+ * {@link androidx.work.ListenableWorker}.
+ *
+ * @param updater The {@link ProgressUpdater} which can handle progress updates.
+ * @return The current {@link TestListenableWorkerBuilder}
+ */
+ @NonNull
+ public TestListenableWorkerBuilder setProgressUpdater(@NonNull ProgressUpdater updater) {
+ mProgressUpdater = updater;
+ return this;
+ }
+
+ /**
* Sets the {@link Executor} that can be used to execute this unit of work.
*
* @param executor The {@link Executor}
@@ -292,7 +314,8 @@
// This is unused for ListenableWorker
getExecutor(),
getTaskExecutor(),
- getWorkerFactory()
+ getWorkerFactory(),
+ getProgressUpdater()
);
WorkerFactory workerFactory = parameters.getWorkerFactory();
diff --git a/work/workmanager-testing/src/main/java/androidx/work/testing/TestProgressUpdater.java b/work/workmanager-testing/src/main/java/androidx/work/testing/TestProgressUpdater.java
new file mode 100644
index 0000000..23464b6
--- /dev/null
+++ b/work/workmanager-testing/src/main/java/androidx/work/testing/TestProgressUpdater.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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.testing;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.work.Data;
+import androidx.work.Logger;
+import androidx.work.ProgressUpdater;
+import androidx.work.impl.utils.futures.SettableFuture;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.UUID;
+
+/**
+ * A {@link ProgressUpdater} which does nothing. Useful in the context of testing.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class TestProgressUpdater implements ProgressUpdater {
+
+ private static final String TAG = Logger.tagWithPrefix("TestProgressUpdater");
+
+ @NonNull
+ @Override
+ public ListenableFuture<Void> updateProgress(
+ @NonNull Context context,
+ @NonNull UUID id,
+ @NonNull Data data) {
+
+ Logger.get().info(TAG, String.format("Updating progress for %s (%s)", id, data));
+ SettableFuture<Void> future = SettableFuture.create();
+ future.set(null);
+ return future;
+ }
+}
diff --git a/work/workmanager/src/androidTest/java/androidx/work/DefaultWorkerFactoryTest.java b/work/workmanager/src/androidTest/java/androidx/work/DefaultWorkerFactoryTest.java
index 332139c..551515e 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/DefaultWorkerFactoryTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/DefaultWorkerFactoryTest.java
@@ -19,6 +19,7 @@
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
import android.content.Context;
@@ -41,11 +42,13 @@
private Context mContext;
private WorkerFactory mDefaultWorkerFactory;
+ private ProgressUpdater mProgressUpdater;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mDefaultWorkerFactory = WorkerFactory.getDefaultWorkerFactory();
+ mProgressUpdater = mock(ProgressUpdater.class);
}
@Test
@@ -66,7 +69,8 @@
1,
executor,
new WorkManagerTaskExecutor(executor),
- mDefaultWorkerFactory));
+ mDefaultWorkerFactory,
+ mProgressUpdater));
assertThat(worker, is(notNullValue()));
assertThat(worker,
is(CoreMatchers.<ListenableWorker>instanceOf(TestWorker.class)));
diff --git a/work/workmanager/src/androidTest/java/androidx/work/DelegatingWorkerFactoryTest.kt b/work/workmanager/src/androidTest/java/androidx/work/DelegatingWorkerFactoryTest.kt
index d84a892..12735f5 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/DelegatingWorkerFactoryTest.kt
+++ b/work/workmanager/src/androidTest/java/androidx/work/DelegatingWorkerFactoryTest.kt
@@ -30,6 +30,7 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
import java.util.UUID
@RunWith(AndroidJUnit4::class)
@@ -38,11 +39,13 @@
private lateinit var context: Context
private lateinit var factory: DelegatingWorkerFactory
+ private lateinit var progressUpdater: ProgressUpdater
@Before
fun setUp() {
context = ApplicationProvider.getApplicationContext()
factory = DelegatingWorkerFactory()
+ progressUpdater = mock(ProgressUpdater::class.java)
}
@Test
@@ -52,7 +55,7 @@
val request = OneTimeWorkRequest.from(TestWorker::class.java)
insertWork(request)
- val params: WorkerParameters = newWorkerParams(factory)
+ val params: WorkerParameters = newWorkerParams(factory, progressUpdater)
val worker = factory.createWorkerWithDefaultFallback(
context,
TestWorker::class.java.name,
@@ -68,7 +71,7 @@
factory = DelegatingWorkerFactory()
val request = OneTimeWorkRequest.from(TestWorker::class.java)
insertWork(request)
- val params: WorkerParameters = newWorkerParams(factory)
+ val params: WorkerParameters = newWorkerParams(factory, progressUpdater)
val worker = factory.createWorkerWithDefaultFallback(
context,
TestWorker::class.java.name,
@@ -79,16 +82,18 @@
assertThat(worker, instanceOf(TestWorker::class.java))
}
- private fun newWorkerParams(factory: WorkerFactory) = WorkerParameters(
- UUID.randomUUID(),
- Data.EMPTY,
- listOf<String>(),
- WorkerParameters.RuntimeExtras(),
- 1,
- SynchronousExecutor(),
- WorkManagerTaskExecutor(SynchronousExecutor()),
- factory
- )
+ private fun newWorkerParams(factory: WorkerFactory, updater: ProgressUpdater) =
+ WorkerParameters(
+ UUID.randomUUID(),
+ Data.EMPTY,
+ listOf<String>(),
+ WorkerParameters.RuntimeExtras(),
+ 1,
+ SynchronousExecutor(),
+ WorkManagerTaskExecutor(SynchronousExecutor()),
+ factory,
+ updater
+ )
}
class NoOpFactory : WorkerFactory() {
diff --git a/work/workmanager/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java b/work/workmanager/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java
index 00014a9..20121dc 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java
@@ -54,6 +54,7 @@
import androidx.work.ListenableWorker;
import androidx.work.OneTimeWorkRequest;
import androidx.work.PeriodicWorkRequest;
+import androidx.work.ProgressUpdater;
import androidx.work.WorkerParameters;
import androidx.work.impl.model.Dependency;
import androidx.work.impl.model.DependencyDao;
@@ -99,6 +100,7 @@
private DependencyDao mDependencyDao;
private Context mContext;
private Scheduler mMockScheduler;
+ private ProgressUpdater mMockProgressUpdater;
private Executor mSynchronousExecutor = new SynchronousExecutor();
@Before
@@ -112,6 +114,7 @@
mWorkSpecDao = mDatabase.workSpecDao();
mDependencyDao = mDatabase.dependencyDao();
mMockScheduler = mock(Scheduler.class);
+ mMockProgressUpdater = mock(ProgressUpdater.class);
}
@Test
@@ -195,7 +198,8 @@
1,
mSynchronousExecutor,
mWorkTaskExecutor,
- mConfiguration.getWorkerFactory()));
+ mConfiguration.getWorkerFactory(),
+ mMockProgressUpdater));
WorkerWrapper workerWrapper = createBuilder(work.getStringId())
.withWorker(usedWorker)
@@ -770,7 +774,8 @@
1,
mSynchronousExecutor,
mWorkTaskExecutor,
- mConfiguration.getWorkerFactory()));
+ mConfiguration.getWorkerFactory(),
+ mMockProgressUpdater));
assertThat(worker, is(notNullValue()));
assertThat(worker.getApplicationContext(), is(equalTo(mContext.getApplicationContext())));
@@ -796,7 +801,8 @@
1,
mSynchronousExecutor,
mWorkTaskExecutor,
- mConfiguration.getWorkerFactory()));
+ mConfiguration.getWorkerFactory(),
+ mMockProgressUpdater));
assertThat(worker, is(notNullValue()));
assertThat(worker.getInputData().getString(key), is(expectedValue));
@@ -813,7 +819,8 @@
1,
mSynchronousExecutor,
mWorkTaskExecutor,
- mConfiguration.getWorkerFactory()));
+ mConfiguration.getWorkerFactory(),
+ mMockProgressUpdater));
assertThat(worker, is(notNullValue()));
assertThat(worker.getInputData().size(), is(0));
@@ -839,7 +846,8 @@
1,
mSynchronousExecutor,
mWorkTaskExecutor,
- mConfiguration.getWorkerFactory()));
+ mConfiguration.getWorkerFactory(),
+ mMockProgressUpdater));
assertThat(worker, is(notNullValue()));
assertThat(worker.getTags(), containsInAnyOrder("one", "two", "three"));
@@ -865,7 +873,8 @@
1,
mSynchronousExecutor,
mWorkTaskExecutor,
- mConfiguration.getWorkerFactory()));
+ mConfiguration.getWorkerFactory(),
+ mMockProgressUpdater));
assertThat(worker, is(notNullValue()));
assertThat(worker.getTriggeredContentAuthorities(),
@@ -949,7 +958,8 @@
1,
Executors.newSingleThreadExecutor(),
mWorkTaskExecutor,
- mConfiguration.getWorkerFactory()));
+ mConfiguration.getWorkerFactory(),
+ mMockProgressUpdater));
WorkerWrapper workerWrapper =
createBuilder(work.getStringId())
@@ -990,7 +1000,8 @@
1,
mSynchronousExecutor,
mWorkTaskExecutor,
- mConfiguration.getWorkerFactory()));
+ mConfiguration.getWorkerFactory(),
+ mMockProgressUpdater));
assertThat(worker, is(notNullValue()));
assertThat(worker.isStopped(), is(false));
@@ -1022,7 +1033,8 @@
1,
mSynchronousExecutor,
mWorkTaskExecutor,
- mConfiguration.getWorkerFactory()));
+ mConfiguration.getWorkerFactory(),
+ mMockProgressUpdater));
assertThat(worker, is(notNullValue()));
assertThat(worker.isStopped(), is(false));
diff --git a/work/workmanager/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java b/work/workmanager/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java
index 2ebd002..f897235 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java
@@ -38,6 +38,7 @@
import androidx.work.DatabaseTest;
import androidx.work.ListenableWorker;
import androidx.work.OneTimeWorkRequest;
+import androidx.work.ProgressUpdater;
import androidx.work.WorkInfo;
import androidx.work.WorkerFactory;
import androidx.work.WorkerParameters;
@@ -85,6 +86,7 @@
private Configuration mConfiguration;
private TaskExecutor mWorkTaskExecutor;
private Scheduler mScheduler;
+ private ProgressUpdater mProgressUpdater;
private Trackers mTracker;
private BatteryChargingTracker mBatteryChargingTracker;
private BatteryNotLowTracker mBatteryNotLowTracker;
@@ -102,6 +104,7 @@
mWorkManagerImpl = mock(WorkManagerImpl.class);
mScheduler = mock(Scheduler.class);
+ mProgressUpdater = mock(ProgressUpdater.class);
when(mWorkManagerImpl.getWorkDatabase()).thenReturn(mDatabase);
when(mWorkManagerImpl.getWorkTaskExecutor()).thenReturn(mWorkTaskExecutor);
when(mWorkManagerImpl.getConfiguration()).thenReturn(mConfiguration);
@@ -261,7 +264,8 @@
1,
executor,
mWorkTaskExecutor,
- workerFactory));
+ workerFactory,
+ mProgressUpdater));
assertThat(worker, is(notNullValue()));
assertThat(worker,
diff --git a/work/workmanager/src/main/java/androidx/work/ListenableWorker.java b/work/workmanager/src/main/java/androidx/work/ListenableWorker.java
index c86c3ae..72a7d5d 100644
--- a/work/workmanager/src/main/java/androidx/work/ListenableWorker.java
+++ b/work/workmanager/src/main/java/androidx/work/ListenableWorker.java
@@ -188,6 +188,19 @@
public abstract @NonNull ListenableFuture<Result> startWork();
/**
+ * Updates {@link ListenableWorker} progress.
+ *
+ * @param data The progress {@link Data}
+ * @return A {@link ListenableFuture} which resolves after progress is persisted.
+ * Cancelling this future is a no-op.
+ */
+ @NonNull
+ public ListenableFuture<Void> setProgress(@NonNull Data data) {
+ return mWorkerParams.getProgressUpdater()
+ .updateProgress(getApplicationContext(), getId(), data);
+ }
+
+ /**
* Returns {@code true} if this Worker has been told to stop. This could be because of an
* explicit cancellation signal by the user, or because the system has decided to preempt the
* task. In these cases, the results of the work will be ignored by WorkManager and it is safe
diff --git a/work/workmanager/src/main/java/androidx/work/ProgressUpdater.java b/work/workmanager/src/main/java/androidx/work/ProgressUpdater.java
new file mode 100644
index 0000000..a090cd8
--- /dev/null
+++ b/work/workmanager/src/main/java/androidx/work/ProgressUpdater.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 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.annotation.NonNull;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.UUID;
+
+/**
+ * Updates progress for a {@link androidx.work.ListenableWorker}.
+ */
+public interface ProgressUpdater {
+
+ /**
+ * @param context The application {@link Context}.
+ * @param id The {@link UUID} identifying the {@link ListenableWorker}
+ * @param data The progress {@link Data}
+ * @return The {@link ListenableFuture} which resolves after progress is persisted.
+ * Cancelling this future is a no-op.
+ */
+ @NonNull
+ ListenableFuture<Void> updateProgress(
+ @NonNull Context context,
+ @NonNull UUID id,
+ @NonNull Data data);
+}
diff --git a/work/workmanager/src/main/java/androidx/work/WorkerParameters.java b/work/workmanager/src/main/java/androidx/work/WorkerParameters.java
index 00d2f18..8c2f5a1 100644
--- a/work/workmanager/src/main/java/androidx/work/WorkerParameters.java
+++ b/work/workmanager/src/main/java/androidx/work/WorkerParameters.java
@@ -48,6 +48,7 @@
private @NonNull Executor mBackgroundExecutor;
private @NonNull TaskExecutor mWorkTaskExecutor;
private @NonNull WorkerFactory mWorkerFactory;
+ private @NonNull ProgressUpdater mProgressUpdater;
/**
* @hide
@@ -61,7 +62,8 @@
@IntRange(from = 0) int runAttemptCount,
@NonNull Executor backgroundExecutor,
@NonNull TaskExecutor workTaskExecutor,
- @NonNull WorkerFactory workerFactory) {
+ @NonNull WorkerFactory workerFactory,
+ @NonNull ProgressUpdater progressUpdater) {
mId = id;
mInputData = inputData;
mTags = new HashSet<>(tags);
@@ -70,6 +72,7 @@
mBackgroundExecutor = backgroundExecutor;
mWorkTaskExecutor = workTaskExecutor;
mWorkerFactory = workerFactory;
+ mProgressUpdater = progressUpdater;
}
/**
@@ -173,6 +176,14 @@
}
/**
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public @NonNull ProgressUpdater getProgressUpdater() {
+ return mProgressUpdater;
+ }
+
+ /**
* Extra runtime information for Workers.
*
* @hide
diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java b/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java
index de5b1c5..f24e179 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java
@@ -47,6 +47,7 @@
import androidx.work.impl.model.WorkSpecDao;
import androidx.work.impl.model.WorkTagDao;
import androidx.work.impl.utils.PackageManagerHelper;
+import androidx.work.impl.utils.WorkProgressUpdater;
import androidx.work.impl.utils.futures.SettableFuture;
import androidx.work.impl.utils.taskexecutor.TaskExecutor;
@@ -224,7 +225,8 @@
mWorkSpec.runAttemptCount,
mConfiguration.getExecutor(),
mWorkTaskExecutor,
- mConfiguration.getWorkerFactory());
+ mConfiguration.getWorkerFactory(),
+ new WorkProgressUpdater(mWorkDatabase, mWorkTaskExecutor));
// Not always creating a worker here, as the WorkerWrapper.Builder can set a worker override
// in test mode.
diff --git a/work/workmanager/src/main/java/androidx/work/impl/utils/WorkProgressUpdater.java b/work/workmanager/src/main/java/androidx/work/impl/utils/WorkProgressUpdater.java
new file mode 100644
index 0000000..38cd978
--- /dev/null
+++ b/work/workmanager/src/main/java/androidx/work/impl/utils/WorkProgressUpdater.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2019 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 android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.work.Data;
+import androidx.work.Logger;
+import androidx.work.ProgressUpdater;
+import androidx.work.WorkInfo.State;
+import androidx.work.impl.WorkDatabase;
+import androidx.work.impl.model.WorkProgress;
+import androidx.work.impl.utils.futures.SettableFuture;
+import androidx.work.impl.utils.taskexecutor.TaskExecutor;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.UUID;
+
+/**
+ * Persists {@link androidx.work.ListenableWorker} progress in a {@link WorkDatabase}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class WorkProgressUpdater implements ProgressUpdater {
+ // Synthetic access
+ static final String TAG = Logger.tagWithPrefix("WorkProgressUpdater");
+
+ // Synthetic access
+ final WorkDatabase mWorkDatabase;
+ // Synthetic access
+ final TaskExecutor mTaskExecutor;
+
+ public WorkProgressUpdater(
+ @NonNull WorkDatabase workDatabase,
+ @NonNull TaskExecutor taskExecutor) {
+ mWorkDatabase = workDatabase;
+ mTaskExecutor = taskExecutor;
+ }
+
+ @NonNull
+ @Override
+ public ListenableFuture<Void> updateProgress(
+ @NonNull final Context context,
+ @NonNull final UUID id,
+ @NonNull final Data data) {
+ final SettableFuture<Void> future = SettableFuture.create();
+ mTaskExecutor.executeOnBackgroundThread(new Runnable() {
+ @Override
+ public void run() {
+ String workSpecId = id.toString();
+ Logger.get().info(TAG, String.format("Updating progress for %s (%s)", id, data));
+ mWorkDatabase.beginTransaction();
+ try {
+ State state = mWorkDatabase.workSpecDao().getState(workSpecId);
+ if (state == null) {
+ Logger.get().warning(TAG,
+ String.format(
+ "Ignoring setProgress(...). WorkSpec (%s) does not exist.",
+ workSpecId));
+ } else if (state.isFinished()) {
+ Logger.get().warning(TAG,
+ String.format(
+ "Ignoring setProgress(...). WorkSpec (%s) has finished "
+ + "execution.",
+ workSpecId));
+ } else {
+ WorkProgress progress = new WorkProgress(workSpecId, data);
+ mWorkDatabase.workProgressDao().insert(progress);
+ }
+ future.set(null);
+ mWorkDatabase.setTransactionSuccessful();
+ } catch (Throwable throwable) {
+ Logger.get().error(TAG, "Error updating Worker progress", throwable);
+ future.setException(throwable);
+ } finally {
+ mWorkDatabase.endTransaction();
+ }
+ }
+ });
+ return future;
+ }
+}