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 package androidx.work;
17 
18 import androidx.annotation.RestrictTo;
19 import androidx.lifecycle.LifecycleOwner;
20 import androidx.lifecycle.LiveData;
21 import androidx.lifecycle.Observer;
22 
23 import com.google.common.util.concurrent.ListenableFuture;
24 
25 import org.jspecify.annotations.NonNull;
26 
27 import java.util.Collections;
28 import java.util.List;
29 
30 /**
31  * A class that allows you to chain together {@link OneTimeWorkRequest}s.  WorkContinuations allow
32  * the user to create arbitrary acyclic graphs of work dependencies.  You can add dependent work to
33  * a WorkContinuation by invoking {@link #then(OneTimeWorkRequest)} or its variants.  This returns a
34  * new WorkContinuation.
35  * <p>
36  * To construct more complex graphs, {@link WorkContinuation#combine(List)} or its
37  * variants can be used to return a WorkContinuation with the input WorkContinuations as
38  * prerequisites.  To create a graph like this:
39  *
40  * <pre>
41  *     A       C
42  *     |       |
43  *     B       D
44  *     |       |
45  *     +-------+
46  *         |
47  *         E    </pre>
48  *
49  * you would write the following:
50  *
51  * <pre class="prettyprint">
52  *  WorkContinuation left = workManager.beginWith(A).then(B);
53  *  WorkContinuation right = workManager.beginWith(C).then(D);
54  *  WorkContinuation final = WorkContinuation.combine(Arrays.asList(left, right)).then(E);
55  *  final.enqueue();
56  *  </pre>
57  *
58  * Not that enqueuing a WorkContinuation enqueues all previously-unenqueued prerequisites.  You must
59  * call {@link #enqueue()} to inform WorkManager to actually enqueue the work graph.  As usual,
60  * enqueues are asynchronous - you can observe or block on the returned {@link Operation} if you
61  * need to be informed about its completion.
62  * <p>
63  * Because of the fluent nature of this class, its existence should be invisible in most cases.
64  */
65 
66 public abstract class WorkContinuation {
67 
68     /**
69      * Adds new {@link OneTimeWorkRequest} items that depend on the successful completion of
70      * all previously added {@link OneTimeWorkRequest}s.
71      *
72      * @param work One or more {@link OneTimeWorkRequest}s to add as dependents
73      * @return A {@link WorkContinuation} that allows for further chaining of dependent
74      *         {@link OneTimeWorkRequest}s
75      */
then(@onNull OneTimeWorkRequest work)76     public final @NonNull WorkContinuation then(@NonNull OneTimeWorkRequest work) {
77         return then(Collections.singletonList(work));
78     }
79 
80     /**
81      * Adds new {@link OneTimeWorkRequest} items that depend on the successful completion
82      * of all previously added {@link OneTimeWorkRequest}s.
83      *
84      * @param work One or more {@link OneTimeWorkRequest} to add as dependents
85      * @return A {@link WorkContinuation} that allows for further chaining of dependent
86      *         {@link OneTimeWorkRequest}s
87      */
then(@onNull List<OneTimeWorkRequest> work)88     public abstract @NonNull WorkContinuation then(@NonNull List<OneTimeWorkRequest> work);
89 
90     /**
91      * Returns a {@link LiveData} list of {@link WorkInfo}s that provide information about the
92      * status of each {@link OneTimeWorkRequest} in this {@link WorkContinuation}, as well as their
93      * prerequisites.  If the state or outputs of any of the work changes, any attached
94      * {@link Observer}s will trigger.
95      *
96      * @return A {@link LiveData} containing a list of {@link WorkInfo}s; you must use
97      *         {@link LiveData#observe(LifecycleOwner, Observer)} to receive updates
98      */
getWorkInfosLiveData()99     public abstract @NonNull LiveData<List<WorkInfo>> getWorkInfosLiveData();
100 
101     /**
102      * Returns a {@link ListenableFuture} of a {@link List} of {@link WorkInfo}s that provides
103      * information about the status of each {@link OneTimeWorkRequest} in this
104      * {@link WorkContinuation}, as well as their prerequisites.
105      *
106      * @return A {@link  ListenableFuture} of a {@link List} of {@link WorkInfo}s
107      */
getWorkInfos()108     public abstract @NonNull ListenableFuture<List<WorkInfo>> getWorkInfos();
109 
110     /**
111      * Enqueues the instance of {@link WorkContinuation} on the background thread.
112      *
113      * @return An {@link Operation} that can be used to determine when the enqueue has completed
114      */
enqueue()115     public abstract @NonNull Operation enqueue();
116 
117     /**
118      * Combines multiple {@link WorkContinuation}s as prerequisites for a new WorkContinuation to
119      * allow for complex chaining.  For example, to create a graph like this:
120      *
121      * <pre>
122      *     A       C
123      *     |       |
124      *     B       D
125      *     |       |
126      *     +-------+
127      *         |
128      *         E    </pre>
129      *
130      * you would write the following:
131      *
132      * <pre>
133      * {@code
134      *  WorkContinuation left = workManager.beginWith(A).then(B);
135      *  WorkContinuation right = workManager.beginWith(C).then(D);
136      *  WorkContinuation final = WorkContinuation.combine(Arrays.asList(left, right)).then(E);
137      *  final.enqueue();}</pre>
138      *
139      * @param continuations One or more {@link WorkContinuation}s that are prerequisites for the
140      *                      return value
141      * @return A {@link WorkContinuation} that allows further chaining
142      */
combine(@onNull List<WorkContinuation> continuations)143     public static @NonNull WorkContinuation combine(@NonNull List<WorkContinuation> continuations) {
144         return continuations.get(0).combineInternal(continuations);
145     }
146 
147     /**
148      */
149     @SuppressWarnings("HiddenAbstractMethod")
150     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
combineInternal( @onNull List<WorkContinuation> continuations)151     protected abstract @NonNull WorkContinuation combineInternal(
152             @NonNull List<WorkContinuation> continuations);
153 }
154