1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.work
18 
19 import android.annotation.SuppressLint
20 import android.app.PendingIntent
21 import android.content.Context
22 import androidx.lifecycle.LiveData
23 import androidx.work.impl.WorkManagerImpl
24 import com.google.common.util.concurrent.ListenableFuture
25 import java.util.UUID
26 import kotlinx.coroutines.flow.Flow
27 
28 /**
29  * WorkManager is the recommended library for persistent work. Scheduled work is guaranteed to
30  * execute sometime after its [Constraints] are met. WorkManager allows observation of work status
31  * and the ability to create complex chains of work.
32  *
33  * WorkManager uses an underlying job dispatching service when available based on the following
34  * criteria:
35  * * Uses JobScheduler for API 23+
36  * * Uses a custom AlarmManager + BroadcastReceiver implementation for API 14-22
37  *
38  * All work must be done in a [ListenableWorker] class. A simple implementation, [Worker], is
39  * recommended as the starting point for most developers. With the optional dependencies, you can
40  * also use `CoroutineWorker` or `RxWorker`. All background work is given a maximum of ten minutes
41  * to finish its execution. After this time has expired, the worker will be signalled to stop.
42  *
43  * There are two types of work supported by WorkManager: [OneTimeWorkRequest] and
44  * [PeriodicWorkRequest]. You can enqueue requests using WorkManager as follows:
45  * ```
46  * WorkManager workManager = WorkManager.getInstance(Context);
47  * workManager.enqueue(new OneTimeWorkRequest.Builder(FooWorker.class).build());
48  * ```
49  *
50  * A [WorkRequest] has an associated id that can be used for lookups and observation as follows:
51  * ```
52  * WorkRequest request = new OneTimeWorkRequest.Builder(FooWorker.class).build();
53  * workManager.enqueue(request);
54  * LiveData<WorkInfo> status = workManager.getWorkInfoByIdLiveData(request.getId());
55  * status.observe(...);
56  * ```
57  *
58  * You can also use the id for cancellation:
59  * ```
60  * WorkRequest request = new OneTimeWorkRequest.Builder(FooWorker.class).build();
61  * workManager.enqueue(request);
62  * workManager.cancelWorkById(request.getId());
63  * ```
64  *
65  * You can chain work as follows:
66  * ```
67  * WorkRequest request1 = new OneTimeWorkRequest.Builder(FooWorker.class).build();
68  * WorkRequest request2 = new OneTimeWorkRequest.Builder(BarWorker.class).build();
69  * WorkRequest request3 = new OneTimeWorkRequest.Builder(BazWorker.class).build();
70  * workManager.beginWith(request1, request2).then(request3).enqueue();
71  * ```
72  *
73  * Each call to [beginWith] returns a [WorkContinuation] upon which you can call
74  * [WorkContinuation.then] with a single [OneTimeWorkRequest] or a list of [OneTimeWorkRequest] to
75  * chain further work. This allows for creation of complex chains of work. For example, to create a
76  * chain like this:
77  * ```
78  *            A
79  *            |
80  *      +----------+
81  *      |          |
82  *      B          C
83  *      |
84  *   +----+
85  *   |    |
86  *   D    E
87  * ```
88  *
89  * you would enqueue them as follows:
90  * ```
91  * WorkContinuation continuation = workManager.beginWith(A);
92  * continuation.then(B).then(D, E).enqueue();  // A is implicitly enqueued here
93  * continuation.then(C).enqueue();
94  * ```
95  *
96  * Work is eligible for execution when all of its prerequisites are complete. If any of its
97  * prerequisites fail or are cancelled, the work will never run.
98  *
99  * WorkRequests can accept [Constraints], inputs (see [Data]), and backoff criteria. WorkRequests
100  * can be tagged with human-readable Strings (see [WorkRequest.Builder.addTag]), and chains of work
101  * can be given a uniquely-identifiable name (see [beginUniqueWork]).
102  *
103  * ### Initializing WorkManager
104  *
105  * By default, WorkManager auto-initializes itself using a built-in `ContentProvider`.
106  * ContentProviders are created and run before the `Application` object, so this allows the
107  * WorkManager singleton to be setup before your code can run in most cases. This is suitable for
108  * most developers. However, you can provide a custom [Configuration] by using
109  * [Configuration.Provider] or [WorkManager.initialize].
110  *
111  * ### Renaming and Removing ListenableWorker Classes
112  *
113  * Exercise caution in renaming classes derived from [ListenableWorker]s. WorkManager stores the
114  * class name in its internal database when the [WorkRequest] is enqueued so it can later create an
115  * instance of that worker when constraints are met. Unless otherwise specified in the WorkManager
116  * [Configuration], this is done in the default [WorkerFactory] which tries to reflectively create
117  * the ListenableWorker object. Therefore, renaming or removing these classes is dangerous - if
118  * there is pending work with the given class, it will fail permanently if the class cannot be
119  * found. If you are using a custom WorkerFactory, make sure you properly handle cases where the
120  * class is not found so that your code does not crash.
121  *
122  * In case it is desirable to rename a class, implement a custom WorkerFactory that instantiates the
123  * right ListenableWorker for the old class name.
124  */
125 // Suppressing Metalava checks for added abstract methods in WorkManager.
126 // WorkManager cannot be extended, because the constructor is marked @Restricted
127 @SuppressLint("AddedAbstractMethod")
128 abstract class WorkManager internal constructor() {
129 
130     companion object {
131         /**
132          * Retrieves the `default` singleton instance of [WorkManager].
133          *
134          * @return The singleton instance of [WorkManager]; this may be `null` in unusual
135          *   circumstances where you have disabled automatic initialization and have failed to
136          *   manually call [initialize].
137          * @throws IllegalStateException If WorkManager is not initialized properly as per the
138          *   exception message.
139          */
140         // `open` modifier was added to avoid errors in WorkManagerImpl:
141         // "WorkManagerImpl cannot override <X> in WorkManager", even though methods are static
142         @Suppress("NON_FINAL_MEMBER_IN_OBJECT")
143         @Deprecated(
144             message = "Use the overload receiving Context",
145             replaceWith = ReplaceWith("WorkManager.getContext(context)"),
146         )
147         @JvmStatic
getInstancenull148         open fun getInstance(): WorkManager {
149             @Suppress("DEPRECATION") val workManager: WorkManager? = WorkManagerImpl.getInstance()
150             checkNotNull(workManager) {
151                 "WorkManager is not initialized properly.  The most " +
152                     "likely cause is that you disabled WorkManagerInitializer in your manifest " +
153                     "but forgot to call WorkManager#initialize in your Application#onCreate or a " +
154                     "ContentProvider."
155             }
156             return workManager
157         }
158 
159         /**
160          * Retrieves the `default` singleton instance of [WorkManager].
161          *
162          * @param context A [Context] for on-demand initialization.
163          * @return The singleton instance of [WorkManager]; this may be `null` in unusual
164          *   circumstances where you have disabled automatic initialization and have failed to
165          *   manually call [initialize].
166          * @throws IllegalStateException If WorkManager is not initialized properly
167          */
168         // `open` modifier was added to avoid errors in WorkManagerImpl:
169         // "WorkManagerImpl cannot override <X> in WorkManager", even though methods are static
170         @Suppress("NON_FINAL_MEMBER_IN_OBJECT")
171         @JvmStatic
getInstancenull172         open fun getInstance(context: Context): WorkManager {
173             return WorkManagerImpl.getInstance(context)
174         }
175 
176         /**
177          * Used to do a one-time initialization of the [WorkManager] singleton with a custom
178          * [Configuration]. By default, this method should not be called because WorkManager is
179          * automatically initialized. To initialize WorkManager yourself, please follow these steps:
180          * * Disable `androidx.work.WorkManagerInitializer` in your manifest.
181          * * Invoke this method in `Application#onCreate` or a `ContentProvider`. Note that this
182          *   method **must** be invoked in one of these two places or you risk getting a
183          *   `NullPointerException` in [getInstance].
184          *
185          * This method throws an [IllegalStateException] when attempting to initialize in direct
186          * boot mode.
187          *
188          * This method throws an exception if it is called multiple times.
189          *
190          * @param context A [Context] object for configuration purposes. Internally, this class will
191          *   call [Context.getApplicationContext], so you may safely pass in any Context without
192          *   risking a memory leak.
193          * @param configuration The [Configuration] for used to set up WorkManager.
194          * @see Configuration.Provider for on-demand initialization.
195          */
196         // `open` modifier was added to avoid errors in WorkManagerImpl:
197         // "WorkManagerImpl cannot override <X> in WorkManager", even though methods are static
198         @Suppress("NON_FINAL_MEMBER_IN_OBJECT")
199         @JvmStatic
initializenull200         open fun initialize(context: Context, configuration: Configuration) {
201             WorkManagerImpl.initialize(context, configuration)
202         }
203 
204         /**
205          * Provides a way to check if [WorkManager] is initialized in this process.
206          *
207          * @return `true` if [WorkManager] has been initialized in this process.
208          */
209         @Suppress("NON_FINAL_MEMBER_IN_OBJECT")
210         @JvmStatic
isInitializednull211         open fun isInitialized(): Boolean = WorkManagerImpl.isInitialized()
212     }
213 
214     /** The [Configuration] instance that [WorkManager] was initialized with. */
215     abstract val configuration: Configuration
216 
217     /**
218      * Enqueues one item for background processing.
219      *
220      * @param request The [WorkRequest] to enqueue
221      * @return An [Operation] that can be used to determine when the enqueue has completed
222      */
223     fun enqueue(request: WorkRequest): Operation {
224         return enqueue(listOf(request))
225     }
226 
227     /**
228      * Enqueues one or more items for background processing.
229      *
230      * @param requests One or more [WorkRequest] to enqueue
231      * @return An [Operation] that can be used to determine when the enqueue has completed
232      */
enqueuenull233     abstract fun enqueue(requests: List<WorkRequest>): Operation
234 
235     /**
236      * Begins a chain with one or more [OneTimeWorkRequest]s, which can be enqueued together in the
237      * future using [WorkContinuation.enqueue].
238      *
239      * If any work in the chain fails or is cancelled, all of its dependent work inherits that state
240      * and will never run.
241      *
242      * @param request One or more [OneTimeWorkRequest] to start a chain of work
243      * @return A [WorkContinuation] that allows for further chaining of dependent
244      *   [OneTimeWorkRequest]
245      */
246     fun beginWith(request: OneTimeWorkRequest): WorkContinuation {
247         return beginWith(listOf(request))
248     }
249 
250     /**
251      * Begins a chain with one or more [OneTimeWorkRequest]s, which can be enqueued together in the
252      * future using [WorkContinuation.enqueue].
253      *
254      * If any work in the chain fails or is cancelled, all of its dependent work inherits that state
255      * and will never run.
256      *
257      * @param requests One or more [OneTimeWorkRequest] to start a chain of work
258      * @return A [WorkContinuation] that allows for further chaining of dependent
259      *   [OneTimeWorkRequest]
260      */
beginWithnull261     abstract fun beginWith(requests: List<OneTimeWorkRequest>): WorkContinuation
262 
263     /**
264      * This method allows you to begin unique chains of work for situations where you only want one
265      * chain with a given name to be active at a time. For example, you may only want one sync
266      * operation to be active. If there is one pending, you can choose to let it run or replace it
267      * with your new work.
268      *
269      * The `uniqueWorkName` uniquely identifies this set of work.
270      *
271      * If this method determines that new work should be enqueued and run, all records of previous
272      * work with `uniqueWorkName` will be pruned. If this method determines that new work should NOT
273      * be run, then the entire chain will be considered a no-op.
274      *
275      * If any work in the chain fails or is cancelled, all of its dependent work inherits that state
276      * and will never run. This is particularly important if you are using `APPEND` as your
277      * [ExistingWorkPolicy].
278      *
279      * @param uniqueWorkName A unique name which for this chain of work
280      * @param existingWorkPolicy An [ExistingWorkPolicy]
281      * @param request The [OneTimeWorkRequest] to enqueue. `REPLACE` ensures that if there is
282      *   pending work labelled with `uniqueWorkName`, it will be cancelled and the new work will
283      *   run. `KEEP` will run the new sequence of work only if there is no pending work labelled
284      *   with `uniqueWorkName`. `APPEND` will create a new sequence of work if there is no existing
285      *   work with `uniqueWorkName`; otherwise, `work` will be added as a child of all leaf nodes
286      *   labelled with `uniqueWorkName`.
287      * @return A [WorkContinuation] that allows further chaining
288      */
289     fun beginUniqueWork(
290         uniqueWorkName: String,
291         existingWorkPolicy: ExistingWorkPolicy,
292         request: OneTimeWorkRequest
293     ): WorkContinuation {
294         return beginUniqueWork(uniqueWorkName, existingWorkPolicy, listOf(request))
295     }
296 
297     /**
298      * This method allows you to begin unique chains of work for situations where you only want one
299      * chain with a given name to be active at a time. For example, you may only want one sync
300      * operation to be active. If there is one pending, you can choose to let it run or replace it
301      * with your new work.
302      *
303      * The `uniqueWorkName` uniquely identifies this set of work.
304      *
305      * If this method determines that new work should be enqueued and run, all records of previous
306      * work with `uniqueWorkName` will be pruned. If this method determines that new work should NOT
307      * be run, then the entire chain will be considered a no-op.
308      *
309      * If any work in the chain fails or is cancelled, all of its dependent work inherits that state
310      * and will never run. This is particularly important if you are using `APPEND` as your
311      * [ExistingWorkPolicy].
312      *
313      * @param uniqueWorkName A unique name which for this chain of work
314      * @param existingWorkPolicy An [ExistingWorkPolicy]; see below for more information
315      * @param requests One or more [OneTimeWorkRequest] to enqueue. `REPLACE` ensures that if there
316      *   is pending work labelled with `uniqueWorkName`, it will be cancelled and the new work will
317      *   run. `KEEP` will run the new sequence of work only if there is no pending work labelled
318      *   with `uniqueWorkName`. `APPEND` will create a new sequence of work if there is no existing
319      *   work with `uniqueWorkName`; otherwise, `work` will be added as a child of all leaf nodes
320      *   labelled with `uniqueWorkName`.
321      * @return A [WorkContinuation] that allows further chaining
322      */
beginUniqueWorknull323     abstract fun beginUniqueWork(
324         uniqueWorkName: String,
325         existingWorkPolicy: ExistingWorkPolicy,
326         requests: List<OneTimeWorkRequest>
327     ): WorkContinuation
328 
329     /**
330      * This method allows you to enqueue `work` requests to a uniquely-named [WorkContinuation],
331      * where only one continuation of a particular name can be active at a time. For example, you
332      * may only want one sync operation to be active. If there is one pending, you can choose to let
333      * it run or replace it with your new work.
334      *
335      * The `uniqueWorkName` uniquely identifies this [WorkContinuation].
336      *
337      * @param uniqueWorkName A unique name which for this operation
338      * @param existingWorkPolicy An [ExistingWorkPolicy]; see below for more information
339      * @param request The [OneTimeWorkRequest]s to enqueue. `REPLACE` ensures that if there is
340      *   pending work labelled with `uniqueWorkName`, it will be cancelled and the new work will
341      *   run. `KEEP` will run the new OneTimeWorkRequests only if there is no pending work labelled
342      *   with `uniqueWorkName`. `APPEND` will append the OneTimeWorkRequests as leaf nodes labelled
343      *   with `uniqueWorkName`.
344      * @return An [Operation] that can be used to determine when the enqueue has completed
345      */
346     open fun enqueueUniqueWork(
347         uniqueWorkName: String,
348         existingWorkPolicy: ExistingWorkPolicy,
349         request: OneTimeWorkRequest
350     ): Operation {
351         return enqueueUniqueWork(uniqueWorkName, existingWorkPolicy, listOf(request))
352     }
353 
354     /**
355      * This method allows you to enqueue `work` requests to a uniquely-named [WorkContinuation],
356      * where only one continuation of a particular name can be active at a time. For example, you
357      * may only want one sync operation to be active. If there is one pending, you can choose to let
358      * it run or replace it with your new work.
359      *
360      * The `uniqueWorkName` uniquely identifies this [WorkContinuation].
361      *
362      * @param uniqueWorkName A unique name which for this operation
363      * @param existingWorkPolicy An [ExistingWorkPolicy]
364      * @param requests [OneTimeWorkRequest]s to enqueue. `REPLACE` ensures that if there is pending
365      *   work labelled with `uniqueWorkName`, it will be cancelled and the new work will run. `KEEP`
366      *   will run the new OneTimeWorkRequests only if there is no pending work labelled with
367      *   `uniqueWorkName`. `APPEND` will append the OneTimeWorkRequests as leaf nodes labelled with
368      *   `uniqueWorkName`.
369      * @return An [Operation] that can be used to determine when the enqueue has completed
370      */
enqueueUniqueWorknull371     abstract fun enqueueUniqueWork(
372         uniqueWorkName: String,
373         existingWorkPolicy: ExistingWorkPolicy,
374         requests: List<OneTimeWorkRequest>
375     ): Operation
376 
377     /**
378      * This method allows you to enqueue a uniquely-named [PeriodicWorkRequest], where only one
379      * PeriodicWorkRequest of a particular name can be active at a time. For example, you may only
380      * want one sync operation to be active. If there is one pending, you can choose to let it run
381      * or replace it with your new work.
382      *
383      * The `uniqueWorkName` uniquely identifies this PeriodicWorkRequest.
384      *
385      * @param uniqueWorkName A unique name which for this operation
386      * @param existingPeriodicWorkPolicy An [ExistingPeriodicWorkPolicy]
387      * @param request A [PeriodicWorkRequest] to enqueue. `REPLACE` ensures that if there is pending
388      *   work labelled with `uniqueWorkName`, it will be cancelled and the new work will run. `KEEP`
389      *   will run the new PeriodicWorkRequest only if there is no pending work labelled with
390      *   `uniqueWorkName`.
391      * @return An [Operation] that can be used to determine when the enqueue has completed
392      */
393     abstract fun enqueueUniquePeriodicWork(
394         uniqueWorkName: String,
395         existingPeriodicWorkPolicy: ExistingPeriodicWorkPolicy,
396         request: PeriodicWorkRequest
397     ): Operation
398 
399     /**
400      * Cancels work with the given id if it isn't finished. Note that cancellation is a best-effort
401      * policy and work that is already executing may continue to run. Upon cancellation,
402      * [ListenableFuture] returned by [ListenableWorker.startWork] will be cancelled. Also
403      * [ListenableWorker.onStopped] will be invoked for any affected workers.
404      *
405      * @param id The id of the work
406      * @return An [Operation] that can be used to determine when the cancelWorkById has completed
407      */
408     abstract fun cancelWorkById(id: UUID): Operation
409 
410     /**
411      * Cancels all unfinished work with the given tag. Note that cancellation is a best-effort
412      * policy and work that is already executing may continue to run. Upon cancellation,
413      * [ListenableFuture] returned by [ListenableWorker.startWork] will be cancelled. Also
414      * [ListenableWorker.onStopped] will be invoked for any affected workers.
415      *
416      * @param tag The tag used to identify the work
417      * @return An [Operation] that can be used to determine when the cancelAllWorkByTag has
418      *   completed
419      */
420     abstract fun cancelAllWorkByTag(tag: String): Operation
421 
422     /**
423      * Cancels all unfinished work in the work chain with the given name. Note that cancellation is
424      * a best-effort policy and work that is already executing may continue to run. Upon
425      * cancellation, [ListenableFuture] returned by [ListenableWorker.startWork] will be cancelled.
426      * Also [ListenableWorker.onStopped] will be invoked for any affected workers.
427      *
428      * @param uniqueWorkName The unique name used to identify the chain of work
429      * @return An [Operation] that can be used to determine when the cancelUniqueWork has completed
430      */
431     abstract fun cancelUniqueWork(uniqueWorkName: String): Operation
432 
433     /**
434      * Cancels all unfinished work. **Use this method with extreme caution!** By invoking it, you
435      * will potentially affect other modules or libraries in your codebase. It is strongly
436      * recommended that you use one of the other cancellation methods at your disposal.
437      *
438      * Upon cancellation, [ListenableFuture] returned by [ListenableWorker.startWork] will be
439      * cancelled. Also [ListenableWorker.onStopped] will be invoked for any affected workers.
440      *
441      * @return An [Operation] that can be used to determine when the cancelAllWork has completed
442      */
443     abstract fun cancelAllWork(): Operation
444 
445     /**
446      * Creates a [PendingIntent] which can be used to cancel a [WorkRequest] with the given `id`.
447      *
448      * @param id The [WorkRequest] id.
449      * @return The [PendingIntent] that can be used to cancel the [WorkRequest].
450      */
451     abstract fun createCancelPendingIntent(id: UUID): PendingIntent
452 
453     /**
454      * Prunes all eligible finished work from the internal database. Eligible work must be finished
455      * ([WorkInfo.State.SUCCEEDED], [WorkInfo.State.FAILED], or [WorkInfo.State.CANCELLED]), with
456      * zero unfinished dependents.
457      *
458      * **Use this method with caution**; by invoking it, you (and any modules and libraries in your
459      * codebase) will no longer be able to observe the [WorkInfo] of the pruned work. You do not
460      * normally need to call this method - WorkManager takes care to auto-prune its work after a
461      * sane period of time. This method also ignores the
462      * [OneTimeWorkRequest.Builder.keepResultsForAtLeast] policy.
463      *
464      * @return An [Operation] that can be used to determine when the pruneWork has completed
465      */
466     abstract fun pruneWork(): Operation
467 
468     /**
469      * Gets a [LiveData] of the last time all work was cancelled. This method is intended for use by
470      * library and module developers who have dependent data in their own repository that must be
471      * updated or deleted in case someone cancels their work without their prior knowledge.
472      *
473      * @return A [LiveData] of the timestamp (`System#getCurrentTimeMillis()`) when [cancelAllWork]
474      *   was last invoked; this timestamp may be `0L` if this never occurred
475      */
476     abstract fun getLastCancelAllTimeMillisLiveData(): LiveData<Long>
477 
478     /**
479      * Gets a [ListenableFuture] of the last time all work was cancelled. This method is intended
480      * for use by library and module developers who have dependent data in their own repository that
481      * must be updated or deleted in case someone cancels their work without their prior knowledge.
482      *
483      * @return A [ListenableFuture] of the timestamp (`System#getCurrentTimeMillis()`) when
484      *   [cancelAllWork] was last invoked; this timestamp may be `0L` if this never occurred
485      */
486     abstract fun getLastCancelAllTimeMillis(): ListenableFuture<Long>
487 
488     /**
489      * Gets a [LiveData] of the [WorkInfo] for a given work id.
490      *
491      * @param id The id of the work
492      * @return A [LiveData] of the [WorkInfo] associated with `id`; note that this [WorkInfo] may be
493      *   `null` if `id` is not known to WorkManager.
494      */
495     abstract fun getWorkInfoByIdLiveData(id: UUID): LiveData<WorkInfo?>
496 
497     /**
498      * Gets a [Flow] of the [WorkInfo] for a given work id.
499      *
500      * @param id The id of the work
501      * @return A [Flow] of the [WorkInfo] associated with `id`; note that this [WorkInfo] may be
502      *   `null` if `id` is not known to WorkManager.
503      */
504     abstract fun getWorkInfoByIdFlow(id: UUID): Flow<WorkInfo?>
505 
506     /**
507      * Gets a [ListenableFuture] of the [WorkInfo] for a given work id.
508      *
509      * @param id The id of the work
510      * @return A [ListenableFuture] of the [WorkInfo] associated with `id`; note that this
511      *   [WorkInfo] may be `null` if `id` is not known to WorkManager
512      */
513     abstract fun getWorkInfoById(id: UUID): ListenableFuture<WorkInfo?>
514 
515     /**
516      * Gets a [LiveData] of the [WorkInfo] for all work for a given tag.
517      *
518      * @param tag The tag of the work
519      * @return A [LiveData] list of [WorkInfo] for work tagged with `tag`
520      */
521     abstract fun getWorkInfosByTagLiveData(tag: String): LiveData<List<WorkInfo>>
522 
523     /**
524      * Gets a [Flow] of the [WorkInfo] for all work for a given tag.
525      *
526      * @param tag The tag of the work
527      * @return A [Flow] list of [WorkInfo] for work tagged with `tag`
528      */
529     abstract fun getWorkInfosByTagFlow(tag: String): Flow<List<WorkInfo>>
530 
531     /**
532      * Gets a [ListenableFuture] of the [WorkInfo] for all work for a given tag.
533      *
534      * @param tag The tag of the work
535      * @return A [ListenableFuture] list of [WorkInfo] for work tagged with `tag`
536      */
537     abstract fun getWorkInfosByTag(tag: String): ListenableFuture<List<WorkInfo>>
538 
539     /**
540      * Gets a [LiveData] of the [WorkInfo] for all work in a work chain with a given unique name.
541      *
542      * @param uniqueWorkName The unique name used to identify the chain of work
543      * @return A [LiveData] of the [WorkInfo] for work in the chain named `uniqueWorkName`
544      */
545     abstract fun getWorkInfosForUniqueWorkLiveData(uniqueWorkName: String): LiveData<List<WorkInfo>>
546 
547     /**
548      * Gets a [Flow] of the [WorkInfo] for all work in a work chain with a given unique name.
549      *
550      * @param uniqueWorkName The unique name used to identify the chain of work
551      * @return A [Flow] of the [WorkInfo] for work in the chain named `uniqueWorkName`
552      */
553     abstract fun getWorkInfosForUniqueWorkFlow(uniqueWorkName: String): Flow<List<WorkInfo>>
554 
555     /**
556      * Gets a [ListenableFuture] of the [WorkInfo] for all work in a work chain with a given unique
557      * name.
558      *
559      * @param uniqueWorkName The unique name used to identify the chain of work
560      * @return A [ListenableFuture] of the [WorkInfo] for work in the chain named `uniqueWorkName`
561      */
562     abstract fun getWorkInfosForUniqueWork(uniqueWorkName: String): ListenableFuture<List<WorkInfo>>
563 
564     /**
565      * Gets the [LiveData] of the [List] of [WorkInfo] for all work referenced by the [WorkQuery]
566      * specification.
567      *
568      * @param workQuery The work query specification
569      * @return A [LiveData] of the [List] of [WorkInfo] for work referenced by this [WorkQuery].
570      */
571     abstract fun getWorkInfosLiveData(workQuery: WorkQuery): LiveData<List<WorkInfo>>
572 
573     /**
574      * Gets the [Flow] of the [List] of [WorkInfo] for all work referenced by the [WorkQuery]
575      * specification.
576      *
577      * @param workQuery The work query specification
578      * @return A [Flow] of the [List] of [WorkInfo] for work referenced by this [WorkQuery].
579      */
580     abstract fun getWorkInfosFlow(workQuery: WorkQuery): Flow<List<WorkInfo>>
581 
582     /**
583      * Gets the [ListenableFuture] of the [List] of [WorkInfo] for all work referenced by the
584      * [WorkQuery] specification.
585      *
586      * @param workQuery The work query specification
587      * @return A [ListenableFuture] of the [List] of [WorkInfo] for work referenced by this
588      *   [WorkQuery].
589      */
590     abstract fun getWorkInfos(workQuery: WorkQuery): ListenableFuture<List<WorkInfo>>
591 
592     /**
593      * Updates the work with the new specification. A [WorkRequest] passed as parameter must have an
594      * id set with [WorkRequest.Builder.setId] that matches an id of the previously enqueued work.
595      *
596      * It preserves enqueue time, e.g. if a work was enqueued 3 hours ago and had 6 hours long
597      * initial delay, after the update it would be still eligible for run in 3 hours, assuming that
598      * initial delay wasn't updated.
599      *
600      * If the work being updated is currently running the returned ListenableFuture will be
601      * completed with [UpdateResult.APPLIED_FOR_NEXT_RUN]. In this case the current run won't be
602      * interrupted and will continue to rely on previous state of the request, e.g. using old
603      * constraints, tags etc. However, on the next run, e.g. retry of one-time Worker or another
604      * iteration of periodic worker, the new worker specification will be used.
605      *
606      * If the one time work that is updated is already finished the returned ListenableFuture will
607      * be completed with [UpdateResult.NOT_APPLIED].
608      *
609      * If update can be applied immediately, e.g. the updated work isn't currently running, the
610      * returned ListenableFuture will be completed with [UpdateResult.APPLIED_IMMEDIATELY].
611      *
612      * If the work with the given id (`request.getId()`) doesn't exist the returned ListenableFuture
613      * will be completed exceptionally with [IllegalArgumentException].
614      *
615      * Worker type can't be changed, [OneTimeWorkRequest] can't be updated to [PeriodicWorkRequest]
616      * and otherwise, the returned ListenableFuture will be completed with
617      * [IllegalArgumentException].
618      *
619      * @param request the new specification for the work.
620      * @return a [ListenableFuture] that will be successfully completed if the update was
621      *   successful. The future will be completed with an exception if the work is already running
622      *   or finished.
623      */
624     // consistent with already existent method like getWorkInfos() in WorkManager
625     @Suppress("AsyncSuffixFuture")
626     abstract fun updateWork(request: WorkRequest): ListenableFuture<UpdateResult>
627 
628     /** An enumeration of results for [WorkManager.updateWork] method. */
629     enum class UpdateResult {
630         /** An update wasn't applied, because `Worker` has already finished. */
631         NOT_APPLIED,
632 
633         /**
634          * An update was successfully applied immediately, meaning the updated work wasn't currently
635          * running in the moment of the request. See [UpdateResult.APPLIED_FOR_NEXT_RUN] for the
636          * case of running worker.
637          */
638         APPLIED_IMMEDIATELY,
639 
640         /**
641          * An update was successfully applied, but the worker being updated was running. This run
642          * isn't interrupted and will continue to rely on previous state of the request, e.g. using
643          * old constraints, tags etc. However, on the next run, e.g. retry of one-time Worker or
644          * another iteration of periodic worker, the new worker specification. will be used.
645          */
646         APPLIED_FOR_NEXT_RUN,
647     }
648 }
649