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 android.support.annotation.NonNull;
19 import android.support.annotation.RequiresApi;
20 import android.support.annotation.RestrictTo;
21 import android.support.annotation.VisibleForTesting;
22 
23 import androidx.work.impl.model.WorkSpec;
24 
25 import java.time.Duration;
26 import java.util.HashSet;
27 import java.util.Set;
28 import java.util.UUID;
29 import java.util.concurrent.TimeUnit;
30 
31 /**
32  * The base interface for work requests.
33  */
34 
35 public abstract class WorkRequest {
36 
37     /**
38      * The default initial backoff time (in milliseconds) for work that has to be retried.
39      */
40     public static final long DEFAULT_BACKOFF_DELAY_MILLIS = 30000L;
41 
42     /**
43      * The maximum backoff time (in milliseconds) for work that has to be retried.
44      */
45     public static final long MAX_BACKOFF_MILLIS = 5 * 60 * 60 * 1000; // 5 hours.
46 
47     /**
48      * The minimum backoff time for work (in milliseconds) that has to be retried.
49      */
50     public static final long MIN_BACKOFF_MILLIS = 10 * 1000; // 10 seconds.
51 
52     private @NonNull UUID mId;
53     private @NonNull WorkSpec mWorkSpec;
54     private @NonNull Set<String> mTags;
55 
56     /**
57      * @hide
58      */
59     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
WorkRequest(@onNull UUID id, @NonNull WorkSpec workSpec, @NonNull Set<String> tags)60     protected WorkRequest(@NonNull UUID id, @NonNull WorkSpec workSpec, @NonNull Set<String> tags) {
61         mId = id;
62         mWorkSpec = workSpec;
63         mTags = tags;
64     }
65 
66     /**
67      * Gets the unique identifier associated with this unit of work.
68      *
69      * @return The identifier for this unit of work
70      */
getId()71     public UUID getId() {
72         return mId;
73     }
74 
75     /**
76      * Gets the string for the unique identifier associated with this unit of work.
77      *
78      * @return The string identifier for this unit of work
79      * @hide
80      */
81     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
getStringId()82     public String getStringId() {
83         return mId.toString();
84     }
85 
86     /**
87      * Gets the {@link WorkSpec} associated with this unit of work.
88      *
89      * @return The {@link WorkSpec} for this unit of work
90      * @hide
91      */
92     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
getWorkSpec()93     public WorkSpec getWorkSpec() {
94         return mWorkSpec;
95     }
96 
97     /**
98      * Gets the tags associated with this unit of work.
99      *
100      * @return The tags for this unit of work
101      * @hide
102      */
103     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
getTags()104     public Set<String> getTags() {
105         return mTags;
106     }
107 
108     /**
109      * A builder for {@link WorkRequest}.
110      *
111      * @param <B> The concrete implementation of of this Builder
112      * @param <W> The type of work object built by this Builder
113      */
114     public abstract static class Builder<B extends Builder, W extends WorkRequest> {
115 
116         boolean mBackoffCriteriaSet = false;
117         UUID mId;
118         WorkSpec mWorkSpec;
119         Set<String> mTags = new HashSet<>();
120 
Builder(@onNull Class<? extends Worker> workerClass)121         public Builder(@NonNull Class<? extends Worker> workerClass) {
122             mId = UUID.randomUUID();
123             mWorkSpec = new WorkSpec(mId.toString(), workerClass.getName());
124             addTag(workerClass.getName());
125         }
126 
127         /**
128          * Change backoff policy and delay for the work.  The default is
129          * {@link BackoffPolicy#EXPONENTIAL} and
130          * {@value WorkRequest#DEFAULT_BACKOFF_DELAY_MILLIS}.  The maximum backoff delay
131          * duration is {@value WorkRequest#MAX_BACKOFF_MILLIS}.
132          *
133          * @param backoffPolicy The {@link BackoffPolicy} to use for work
134          * @param backoffDelay Time to wait before restarting {@link Worker} in {@code timeUnit}
135          *                     units
136          * @param timeUnit The {@link TimeUnit} for {@code backoffDelay}
137          * @return The current {@link Builder}
138          */
setBackoffCriteria( @onNull BackoffPolicy backoffPolicy, long backoffDelay, @NonNull TimeUnit timeUnit)139         public B setBackoffCriteria(
140                 @NonNull BackoffPolicy backoffPolicy,
141                 long backoffDelay,
142                 @NonNull TimeUnit timeUnit) {
143             mBackoffCriteriaSet = true;
144             mWorkSpec.backoffPolicy = backoffPolicy;
145             mWorkSpec.setBackoffDelayDuration(timeUnit.toMillis(backoffDelay));
146             return getThis();
147         }
148 
149         /**
150          * Add constraints to the {@link OneTimeWorkRequest}.
151          *
152          * @param constraints The constraints for the work
153          * @return The current {@link Builder}
154          */
setConstraints(@onNull Constraints constraints)155         public B setConstraints(@NonNull Constraints constraints) {
156             mWorkSpec.constraints = constraints;
157             return getThis();
158         }
159 
160         /**
161          * Add input {@link Data} to the work.
162          *
163          * @param inputData key/value pairs that will be provided to the {@link Worker} class
164          * @return The current {@link Builder}
165          */
setInputData(@onNull Data inputData)166         public B setInputData(@NonNull Data inputData) {
167             mWorkSpec.input = inputData;
168             return getThis();
169         }
170 
171         /**
172          * Add an optional tag for the work.  This is particularly useful for modules or
173          * libraries who want to query for or cancel all of their own work.
174          *
175          * @param tag A tag for identifying the work in queries.
176          * @return The current {@link Builder}
177          */
addTag(@onNull String tag)178         public B addTag(@NonNull String tag) {
179             mTags.add(tag);
180             return getThis();
181         }
182 
183         /**
184          * Specifies that the results of this work should be kept for at least the specified amount
185          * of time.  After this time has elapsed, the results may be pruned at the discretion of
186          * WorkManager when there are no pending dependent jobs.
187          *
188          * When the results of a work are pruned, it becomes impossible to query for its
189          * {@link WorkStatus}.
190          *
191          * Specifying a long duration here may adversely affect performance in terms of app storage
192          * and database query time.
193          *
194          * @param duration The minimum duration of time (in {@code timeUnit} units) to keep the
195          *                 results of this work
196          * @param timeUnit The unit of time for {@code duration}
197          * @return The current {@link Builder}
198          */
keepResultsForAtLeast(long duration, @NonNull TimeUnit timeUnit)199         public B keepResultsForAtLeast(long duration, @NonNull TimeUnit timeUnit) {
200             mWorkSpec.minimumRetentionDuration = timeUnit.toMillis(duration);
201             return getThis();
202         }
203 
204         /**
205          * Specifies that the results of this work should be kept for at least the specified amount
206          * of time.  After this time has elapsed, the results may be pruned at the discretion of
207          * WorkManager when there are no pending dependent jobs.
208          *
209          * When the results of a work are pruned, it becomes impossible to query for its
210          * {@link WorkStatus}.
211          *
212          * Specifying a long duration here may adversely affect performance in terms of app storage
213          * and database query time.
214          *
215          * @param duration The minimum duration of time to keep the results of this work
216          * @return The current {@link Builder}
217          */
218         @RequiresApi(26)
keepResultsForAtLeast(@onNull Duration duration)219         public B keepResultsForAtLeast(@NonNull Duration duration) {
220             mWorkSpec.minimumRetentionDuration = duration.toMillis();
221             return getThis();
222         }
223 
224         /**
225          * Builds this work object.
226          *
227          * @return The concrete implementation of the work associated with this builder
228          */
build()229         public abstract W build();
230 
getThis()231         abstract B getThis();
232 
233         /**
234          * Set the initial state for this work.  Used in testing only.
235          *
236          * @param state The {@link State} to set
237          * @return The current {@link Builder}
238          * @hide
239          */
240         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
241         @VisibleForTesting
setInitialState(@onNull State state)242         public B setInitialState(@NonNull State state) {
243             mWorkSpec.state = state;
244             return getThis();
245         }
246 
247         /**
248          * Set the initial run attempt count for this work.  Used in testing only.
249          *
250          * @param runAttemptCount The initial run attempt count
251          * @return The current {@link Builder}
252          * @hide
253          */
254         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
255         @VisibleForTesting
setInitialRunAttemptCount(int runAttemptCount)256         public B setInitialRunAttemptCount(int runAttemptCount) {
257             mWorkSpec.runAttemptCount = runAttemptCount;
258             return getThis();
259         }
260 
261         /**
262          * Set the period start time for this work. Used in testing only.
263          *
264          * @param periodStartTime the period start time in {@code timeUnit} units
265          * @param timeUnit The {@link TimeUnit} for {@code periodStartTime}
266          * @return The current {@link Builder}
267          * @hide
268          */
269         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
270         @VisibleForTesting
setPeriodStartTime(long periodStartTime, @NonNull TimeUnit timeUnit)271         public B setPeriodStartTime(long periodStartTime, @NonNull TimeUnit timeUnit) {
272             mWorkSpec.periodStartTime = timeUnit.toMillis(periodStartTime);
273             return getThis();
274         }
275 
276         /**
277          * Set when the scheduler actually schedules the worker.
278          *
279          * @param scheduleRequestedAt The time at which the scheduler scheduled a worker.
280          * @param timeUnit            The {@link TimeUnit} for {@code scheduleRequestedAt}
281          * @return The current {@link Builder}
282          * @hide
283          */
284         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
285         @VisibleForTesting
setScheduleRequestedAt( long scheduleRequestedAt, @NonNull TimeUnit timeUnit)286         public B setScheduleRequestedAt(
287                 long scheduleRequestedAt,
288                 @NonNull TimeUnit timeUnit) {
289             mWorkSpec.scheduleRequestedAt = timeUnit.toMillis(scheduleRequestedAt);
290             return getThis();
291         }
292     }
293 }
294