blob: 4cbaf6cbf087f48c960e34341bbf2e0c6ffa9a5d [file] [log] [blame]
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001/*
2 * Copyright (C) 2014 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
Christopher Tate7060b042014-06-09 19:50:00 -070017package android.app.job;
Matthew Williams6e31c5c2014-04-11 15:49:16 -070018
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080019import android.annotation.NonNull;
20import android.annotation.Nullable;
Christopher Tatefa380e92014-05-19 13:46:29 -070021import android.content.ComponentName;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080022import android.net.Uri;
Matthew Williams6e31c5c2014-04-11 15:49:16 -070023import android.os.Parcel;
24import android.os.Parcelable;
Matthew Williams3d86fd22014-05-16 18:02:17 -070025import android.os.PersistableBundle;
Shreyas Basargee96c3b72016-01-29 19:25:51 +000026import android.util.Log;
Shreyas Basarged8bf6b92016-02-02 23:45:14 +000027import static android.util.TimeUtils.formatForLogging;
Matthew Williams6e31c5c2014-04-11 15:49:16 -070028
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080029import java.util.ArrayList;
30
Matthew Williams6e31c5c2014-04-11 15:49:16 -070031/**
Christopher Tate7060b042014-06-09 19:50:00 -070032 * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
Matthew Williams6e31c5c2014-04-11 15:49:16 -070033 * parameters required to schedule work against the calling application. These are constructed
Christopher Tate7060b042014-06-09 19:50:00 -070034 * using the {@link JobInfo.Builder}.
Matthew Williams9ae3dbe2014-08-21 13:47:47 -070035 * You must specify at least one sort of constraint on the JobInfo object that you are creating.
36 * The goal here is to provide the scheduler with high-level semantics about the work you want to
37 * accomplish. Doing otherwise with throw an exception in your app.
Matthew Williams6e31c5c2014-04-11 15:49:16 -070038 */
Christopher Tate7060b042014-06-09 19:50:00 -070039public class JobInfo implements Parcelable {
Shreyas Basargee96c3b72016-01-29 19:25:51 +000040 private static String TAG = "JobInfo";
Matthew Williamsd1c06752014-08-22 14:15:28 -070041 /** Default. */
42 public static final int NETWORK_TYPE_NONE = 0;
43 /** This job requires network connectivity. */
44 public static final int NETWORK_TYPE_ANY = 1;
45 /** This job requires network connectivity that is unmetered. */
46 public static final int NETWORK_TYPE_UNMETERED = 2;
Matthew Williams6e31c5c2014-04-11 15:49:16 -070047
48 /**
Christopher Tate7060b042014-06-09 19:50:00 -070049 * Amount of backoff a job has initially by default, in milliseconds.
Matthew Williams3d86fd22014-05-16 18:02:17 -070050 */
Matthew Williamsd1c06752014-08-22 14:15:28 -070051 public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 30 seconds.
52
53 /**
54 * Maximum backoff we allow for a job, in milliseconds.
55 */
56 public static final long MAX_BACKOFF_DELAY_MILLIS = 5 * 60 * 60 * 1000; // 5 hours.
57
58 /**
59 * Linearly back-off a failed job. See
60 * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}
61 * retry_time(current_time, num_failures) =
62 * current_time + initial_backoff_millis * num_failures, num_failures >= 1
63 */
64 public static final int BACKOFF_POLICY_LINEAR = 0;
65
66 /**
67 * Exponentially back-off a failed job. See
68 * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}
69 *
70 * retry_time(current_time, num_failures) =
71 * current_time + initial_backoff_millis * 2 ^ (num_failures - 1), num_failures >= 1
72 */
73 public static final int BACKOFF_POLICY_EXPONENTIAL = 1;
Matthew Williams3d86fd22014-05-16 18:02:17 -070074
Shreyas Basarge89ee6182015-12-17 15:16:36 +000075 /* Minimum interval for a periodic job, in milliseconds. */
76 public static final long MIN_PERIOD_MILLIS = 60 * 60 * 1000L; // 60 minutes
77 /* Minimum flex for a periodic job, in milliseconds. */
78 public static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
79
Matthew Williams3d86fd22014-05-16 18:02:17 -070080 /**
81 * Default type of backoff.
82 * @hide
83 */
Matthew Williamsd1c06752014-08-22 14:15:28 -070084 public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL;
Matthew Williams6e31c5c2014-04-11 15:49:16 -070085
Dianne Hackborn1085ff62016-02-23 17:04:58 -080086 /**
87 * Default of {@link #getPriority}.
88 * @hide
89 */
90 public static final int PRIORITY_DEFAULT = 0;
91
92 /**
93 * Value of {@link #getPriority} for expedited syncs.
94 * @hide
95 */
96 public static final int PRIORITY_SYNC_EXPEDITED = 10;
97
98 /**
99 * Value of {@link #getPriority} for first time initialization syncs.
100 * @hide
101 */
102 public static final int PRIORITY_SYNC_INITIALIZATION = 20;
103
104 /**
105 * Value of {@link #getPriority} for the current foreground app (overrides the supplied
106 * JobInfo priority if it is smaller).
107 * @hide
108 */
109 public static final int PRIORITY_FOREGROUND_APP = 30;
110
Christopher Tate7060b042014-06-09 19:50:00 -0700111 private final int jobId;
Matthew Williams3d86fd22014-05-16 18:02:17 -0700112 private final PersistableBundle extras;
Matthew Williams6de79e22014-05-01 10:47:00 -0700113 private final ComponentName service;
114 private final boolean requireCharging;
115 private final boolean requireDeviceIdle;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800116 private final TriggerContentUri[] triggerContentUris;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700117 private final boolean hasEarlyConstraint;
118 private final boolean hasLateConstraint;
Matthew Williamsd1c06752014-08-22 14:15:28 -0700119 private final int networkType;
Matthew Williams6de79e22014-05-01 10:47:00 -0700120 private final long minLatencyMillis;
121 private final long maxExecutionDelayMillis;
122 private final boolean isPeriodic;
Matthew Williams900c67f2014-07-09 12:46:53 -0700123 private final boolean isPersisted;
Matthew Williams6de79e22014-05-01 10:47:00 -0700124 private final long intervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000125 private final long flexMillis;
Matthew Williams6de79e22014-05-01 10:47:00 -0700126 private final long initialBackoffMillis;
127 private final int backoffPolicy;
Shreyas Basarge5db09082016-01-07 13:38:29 +0000128 private final int priority;
Matthew Williams6de79e22014-05-01 10:47:00 -0700129
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700130 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700131 * Unique job id associated with this class. This is assigned to your job by the scheduler.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700132 */
Matthew Williams9b9244b62014-05-14 11:06:04 -0700133 public int getId() {
Christopher Tate7060b042014-06-09 19:50:00 -0700134 return jobId;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700135 }
136
137 /**
138 * Bundle of extras which are returned to your application at execution time.
139 */
Matthew Williams3d86fd22014-05-16 18:02:17 -0700140 public PersistableBundle getExtras() {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700141 return extras;
142 }
143
144 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700145 * Name of the service endpoint that will be called back into by the JobScheduler.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700146 */
Matthew Williams6de79e22014-05-01 10:47:00 -0700147 public ComponentName getService() {
148 return service;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700149 }
150
Shreyas Basarge5db09082016-01-07 13:38:29 +0000151 /** @hide */
152 public int getPriority() {
153 return priority;
154 }
155
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700156 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700157 * Whether this job needs the device to be plugged in.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700158 */
159 public boolean isRequireCharging() {
160 return requireCharging;
161 }
162
163 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700164 * Whether this job needs the device to be in an Idle maintenance window.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700165 */
166 public boolean isRequireDeviceIdle() {
167 return requireDeviceIdle;
168 }
169
170 /**
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800171 * Which content: URIs must change for the job to be scheduled. Returns null
172 * if there are none required.
173 */
174 @Nullable
175 public TriggerContentUri[] getTriggerContentUris() {
176 return triggerContentUris;
177 }
178
179 /**
Matthew Williamsd1c06752014-08-22 14:15:28 -0700180 * One of {@link android.app.job.JobInfo#NETWORK_TYPE_ANY},
181 * {@link android.app.job.JobInfo#NETWORK_TYPE_NONE}, or
182 * {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700183 */
Matthew Williamsd1c06752014-08-22 14:15:28 -0700184 public int getNetworkType() {
185 return networkType;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700186 }
187
188 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700189 * Set for a job that does not recur periodically, to specify a delay after which the job
190 * will be eligible for execution. This value is not set if the job recurs periodically.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700191 */
192 public long getMinLatencyMillis() {
193 return minLatencyMillis;
194 }
195
196 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700197 * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the job recurs
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700198 * periodically.
199 */
200 public long getMaxExecutionDelayMillis() {
201 return maxExecutionDelayMillis;
202 }
203
204 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700205 * Track whether this job will repeat with a given period.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700206 */
207 public boolean isPeriodic() {
208 return isPeriodic;
209 }
210
211 /**
Matthew Williams900c67f2014-07-09 12:46:53 -0700212 * @return Whether or not this job should be persisted across device reboots.
213 */
214 public boolean isPersisted() {
215 return isPersisted;
216 }
217
218 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700219 * Set to the interval between occurrences of this job. This value is <b>not</b> set if the
220 * job does not recur periodically.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700221 */
222 public long getIntervalMillis() {
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000223 return intervalMillis >= MIN_PERIOD_MILLIS ? intervalMillis : MIN_PERIOD_MILLIS;
224 }
225
226 /**
227 * Flex time for this job. Only valid if this is a periodic job.
228 */
229 public long getFlexMillis() {
230 long interval = getIntervalMillis();
231 long percentClamp = 5 * interval / 100;
232 long clampedFlex = Math.max(flexMillis, Math.max(percentClamp, MIN_FLEX_MILLIS));
233 return clampedFlex <= interval ? clampedFlex : interval;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700234 }
235
236 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700237 * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
238 * will be increased depending on the backoff policy specified at job creation time. Defaults
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700239 * to 5 seconds.
240 */
241 public long getInitialBackoffMillis() {
242 return initialBackoffMillis;
243 }
244
245 /**
Matthew Williamsd1c06752014-08-22 14:15:28 -0700246 * One of either {@link android.app.job.JobInfo#BACKOFF_POLICY_EXPONENTIAL}, or
247 * {@link android.app.job.JobInfo#BACKOFF_POLICY_LINEAR}, depending on which criteria you set
248 * when creating this job.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700249 */
250 public int getBackoffPolicy() {
251 return backoffPolicy;
252 }
253
Matthew Williams9b9244b62014-05-14 11:06:04 -0700254 /**
255 * User can specify an early constraint of 0L, which is valid, so we keep track of whether the
256 * function was called at all.
257 * @hide
258 */
259 public boolean hasEarlyConstraint() {
260 return hasEarlyConstraint;
261 }
262
263 /**
264 * User can specify a late constraint of 0L, which is valid, so we keep track of whether the
265 * function was called at all.
266 * @hide
267 */
268 public boolean hasLateConstraint() {
269 return hasLateConstraint;
270 }
271
Christopher Tate7060b042014-06-09 19:50:00 -0700272 private JobInfo(Parcel in) {
273 jobId = in.readInt();
Matthew Williams3d86fd22014-05-16 18:02:17 -0700274 extras = in.readPersistableBundle();
Matthew Williamseffacfa2014-06-05 20:56:40 -0700275 service = in.readParcelable(null);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700276 requireCharging = in.readInt() == 1;
277 requireDeviceIdle = in.readInt() == 1;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800278 triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR);
Matthew Williamsd1c06752014-08-22 14:15:28 -0700279 networkType = in.readInt();
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700280 minLatencyMillis = in.readLong();
281 maxExecutionDelayMillis = in.readLong();
282 isPeriodic = in.readInt() == 1;
Matthew Williams900c67f2014-07-09 12:46:53 -0700283 isPersisted = in.readInt() == 1;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700284 intervalMillis = in.readLong();
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000285 flexMillis = in.readLong();
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700286 initialBackoffMillis = in.readLong();
287 backoffPolicy = in.readInt();
Matthew Williams9b9244b62014-05-14 11:06:04 -0700288 hasEarlyConstraint = in.readInt() == 1;
289 hasLateConstraint = in.readInt() == 1;
Shreyas Basarge5db09082016-01-07 13:38:29 +0000290 priority = in.readInt();
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700291 }
292
Christopher Tate7060b042014-06-09 19:50:00 -0700293 private JobInfo(JobInfo.Builder b) {
294 jobId = b.mJobId;
Matthew Williamseffacfa2014-06-05 20:56:40 -0700295 extras = b.mExtras;
Christopher Tate7060b042014-06-09 19:50:00 -0700296 service = b.mJobService;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700297 requireCharging = b.mRequiresCharging;
298 requireDeviceIdle = b.mRequiresDeviceIdle;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800299 triggerContentUris = b.mTriggerContentUris != null
300 ? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()])
301 : null;
Matthew Williamsd1c06752014-08-22 14:15:28 -0700302 networkType = b.mNetworkType;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700303 minLatencyMillis = b.mMinLatencyMillis;
304 maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
305 isPeriodic = b.mIsPeriodic;
Matthew Williams900c67f2014-07-09 12:46:53 -0700306 isPersisted = b.mIsPersisted;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700307 intervalMillis = b.mIntervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000308 flexMillis = b.mFlexMillis;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700309 initialBackoffMillis = b.mInitialBackoffMillis;
310 backoffPolicy = b.mBackoffPolicy;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700311 hasEarlyConstraint = b.mHasEarlyConstraint;
312 hasLateConstraint = b.mHasLateConstraint;
Shreyas Basarge5db09082016-01-07 13:38:29 +0000313 priority = b.mPriority;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700314 }
315
316 @Override
317 public int describeContents() {
318 return 0;
319 }
320
321 @Override
322 public void writeToParcel(Parcel out, int flags) {
Christopher Tate7060b042014-06-09 19:50:00 -0700323 out.writeInt(jobId);
Matthew Williams3d86fd22014-05-16 18:02:17 -0700324 out.writePersistableBundle(extras);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700325 out.writeParcelable(service, flags);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700326 out.writeInt(requireCharging ? 1 : 0);
327 out.writeInt(requireDeviceIdle ? 1 : 0);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800328 out.writeTypedArray(triggerContentUris, flags);
Matthew Williamsd1c06752014-08-22 14:15:28 -0700329 out.writeInt(networkType);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700330 out.writeLong(minLatencyMillis);
331 out.writeLong(maxExecutionDelayMillis);
332 out.writeInt(isPeriodic ? 1 : 0);
Matthew Williams900c67f2014-07-09 12:46:53 -0700333 out.writeInt(isPersisted ? 1 : 0);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700334 out.writeLong(intervalMillis);
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000335 out.writeLong(flexMillis);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700336 out.writeLong(initialBackoffMillis);
337 out.writeInt(backoffPolicy);
Matthew Williams9b9244b62014-05-14 11:06:04 -0700338 out.writeInt(hasEarlyConstraint ? 1 : 0);
339 out.writeInt(hasLateConstraint ? 1 : 0);
Shreyas Basarge5db09082016-01-07 13:38:29 +0000340 out.writeInt(priority);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700341 }
342
Christopher Tate7060b042014-06-09 19:50:00 -0700343 public static final Creator<JobInfo> CREATOR = new Creator<JobInfo>() {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700344 @Override
Christopher Tate7060b042014-06-09 19:50:00 -0700345 public JobInfo createFromParcel(Parcel in) {
346 return new JobInfo(in);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700347 }
348
349 @Override
Christopher Tate7060b042014-06-09 19:50:00 -0700350 public JobInfo[] newArray(int size) {
351 return new JobInfo[size];
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700352 }
353 };
354
Matthew Williamsee410da2014-07-25 11:30:40 -0700355 @Override
356 public String toString() {
357 return "(job:" + jobId + "/" + service.flattenToShortString() + ")";
358 }
359
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800360 /**
361 * Information about a content URI modification that a job would like to
362 * trigger on.
363 */
364 public static final class TriggerContentUri implements Parcelable {
365 private final Uri mUri;
366 private final int mFlags;
367
368 /**
369 * Flag for trigger: also trigger if any descendants of the given URI change.
370 * Corresponds to the <var>notifyForDescendants</var> of
371 * {@link android.content.ContentResolver#registerContentObserver}.
372 */
373 public static final int FLAG_NOTIFY_FOR_DESCENDANTS = 1<<0;
374
375 /**
376 * Create a new trigger description.
377 * @param uri The URI to observe. Must be non-null.
378 * @param flags Optional flags for the observer, either 0 or
379 * {@link #FLAG_NOTIFY_FOR_DESCENDANTS}.
380 */
381 public TriggerContentUri(@NonNull Uri uri, int flags) {
382 mUri = uri;
383 mFlags = flags;
384 }
385
386 /**
387 * Return the Uri this trigger was created for.
388 */
389 public Uri getUri() {
390 return mUri;
391 }
392
393 /**
394 * Return the flags supplied for the trigger.
395 */
396 public int getFlags() {
397 return mFlags;
398 }
399
400 private TriggerContentUri(Parcel in) {
401 mUri = Uri.CREATOR.createFromParcel(in);
402 mFlags = in.readInt();
403 }
404
405 @Override
406 public int describeContents() {
407 return 0;
408 }
409
410 @Override
411 public void writeToParcel(Parcel out, int flags) {
412 mUri.writeToParcel(out, flags);
413 out.writeInt(mFlags);
414 }
415
416 public static final Creator<TriggerContentUri> CREATOR = new Creator<TriggerContentUri>() {
417 @Override
418 public TriggerContentUri createFromParcel(Parcel in) {
419 return new TriggerContentUri(in);
420 }
421
422 @Override
423 public TriggerContentUri[] newArray(int size) {
424 return new TriggerContentUri[size];
425 }
426 };
427 }
428
Christopher Tate7060b042014-06-09 19:50:00 -0700429 /** Builder class for constructing {@link JobInfo} objects. */
Matthew Williams9b9244b62014-05-14 11:06:04 -0700430 public static final class Builder {
Christopher Tate7060b042014-06-09 19:50:00 -0700431 private int mJobId;
Matthew Williams3d86fd22014-05-16 18:02:17 -0700432 private PersistableBundle mExtras = PersistableBundle.EMPTY;
Christopher Tate7060b042014-06-09 19:50:00 -0700433 private ComponentName mJobService;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800434 private int mPriority = PRIORITY_DEFAULT;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700435 // Requirements.
436 private boolean mRequiresCharging;
437 private boolean mRequiresDeviceIdle;
Matthew Williamsd1c06752014-08-22 14:15:28 -0700438 private int mNetworkType;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800439 private ArrayList<TriggerContentUri> mTriggerContentUris;
Matthew Williams900c67f2014-07-09 12:46:53 -0700440 private boolean mIsPersisted;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700441 // One-off parameters.
442 private long mMinLatencyMillis;
443 private long mMaxExecutionDelayMillis;
444 // Periodic parameters.
445 private boolean mIsPeriodic;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700446 private boolean mHasEarlyConstraint;
447 private boolean mHasLateConstraint;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700448 private long mIntervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000449 private long mFlexMillis;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700450 // Back-off parameters.
Matthew Williams3d86fd22014-05-16 18:02:17 -0700451 private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS;
452 private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700453 /** Easy way to track whether the client has tried to set a back-off policy. */
454 private boolean mBackoffPolicySet = false;
455
456 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700457 * @param jobId Application-provided id for this job. Subsequent calls to cancel, or
458 * jobs created with the same jobId, will update the pre-existing job with
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700459 * the same id.
Christopher Tate7060b042014-06-09 19:50:00 -0700460 * @param jobService The endpoint that you implement that will receive the callback from the
461 * JobScheduler.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700462 */
Christopher Tate7060b042014-06-09 19:50:00 -0700463 public Builder(int jobId, ComponentName jobService) {
464 mJobService = jobService;
465 mJobId = jobId;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700466 }
467
468 /**
Shreyas Basarge5db09082016-01-07 13:38:29 +0000469 * @hide
470 */
471 public Builder setPriority(int priority) {
472 mPriority = priority;
473 return this;
474 }
475
476 /**
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700477 * Set optional extras. This is persisted, so we only allow primitive types.
478 * @param extras Bundle containing extras you want the scheduler to hold on to for you.
479 */
Matthew Williams3d86fd22014-05-16 18:02:17 -0700480 public Builder setExtras(PersistableBundle extras) {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700481 mExtras = extras;
482 return this;
483 }
484
485 /**
Matthew Williamsd1c06752014-08-22 14:15:28 -0700486 * Set some description of the kind of network type your job needs to have.
487 * Not calling this function means the network is not necessary, as the default is
488 * {@link #NETWORK_TYPE_NONE}.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700489 * Bear in mind that calling this function defines network as a strict requirement for your
Matthew Williamsd1c06752014-08-22 14:15:28 -0700490 * job. If the network requested is not available your job will never run. See
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700491 * {@link #setOverrideDeadline(long)} to change this behaviour.
492 */
Matthew Williamsd1c06752014-08-22 14:15:28 -0700493 public Builder setRequiredNetworkType(int networkType) {
494 mNetworkType = networkType;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700495 return this;
496 }
497
Christopher Tate7060b042014-06-09 19:50:00 -0700498 /**
499 * Specify that to run this job, the device needs to be plugged in. This defaults to
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700500 * false.
Christopher Tate7060b042014-06-09 19:50:00 -0700501 * @param requiresCharging Whether or not the device is plugged in.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700502 */
503 public Builder setRequiresCharging(boolean requiresCharging) {
504 mRequiresCharging = requiresCharging;
505 return this;
506 }
507
508 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700509 * Specify that to run, the job needs the device to be in idle mode. This defaults to
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700510 * false.
511 * <p>Idle mode is a loose definition provided by the system, which means that the device
512 * is not in use, and has not been in use for some time. As such, it is a good time to
Christopher Tate7060b042014-06-09 19:50:00 -0700513 * perform resource heavy jobs. Bear in mind that battery usage will still be attributed
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700514 * to your application, and surfaced to the user in battery stats.</p>
515 * @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
516 * window.
517 */
518 public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
519 mRequiresDeviceIdle = requiresDeviceIdle;
520 return this;
521 }
522
523 /**
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800524 * Add a new content: URI that will be monitored with a
525 * {@link android.database.ContentObserver}, and will cause the job to execute if changed.
526 * If you have any trigger content URIs associated with a job, it will not execute until
527 * there has been a change report for one or more of them.
528 * <p>Note that trigger URIs can not be used in combination with
529 * {@link #setPeriodic(long)} or {@link #setPersisted(boolean)}. To continually monitor
530 * for content changes, you need to schedule a new JobInfo observing the same URIs
531 * before you finish execution of the JobService handling the most recent changes.</p>
532 * @param uri The content: URI to monitor.
533 */
534 public Builder addTriggerContentUri(@NonNull TriggerContentUri uri) {
535 if (mTriggerContentUris == null) {
536 mTriggerContentUris = new ArrayList<>();
537 }
538 mTriggerContentUris.add(uri);
539 return this;
540 }
541
542 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700543 * Specify that this job should recur with the provided interval, not more than once per
544 * period. You have no control over when within this interval this job will be executed,
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700545 * only the guarantee that it will be executed at most once within this interval.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700546 * Setting this function on the builder with {@link #setMinimumLatency(long)} or
547 * {@link #setOverrideDeadline(long)} will result in an error.
Christopher Tate7060b042014-06-09 19:50:00 -0700548 * @param intervalMillis Millisecond interval for which this job will repeat.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700549 */
550 public Builder setPeriodic(long intervalMillis) {
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000551 return setPeriodic(intervalMillis, intervalMillis);
552 }
553
554 /**
555 * Specify that this job should recur with the provided interval and flex. The job can
556 * execute at any time in a window of flex length at the end of the period.
Shreyas Basargee96c3b72016-01-29 19:25:51 +0000557 * @param intervalMillis Millisecond interval for which this job will repeat. A minimum
558 * value of {@link #MIN_PERIOD_MILLIS} is enforced.
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000559 * @param flexMillis Millisecond flex for this job. Flex is clamped to be at least
560 * {@link #MIN_FLEX_MILLIS} or 5 percent of the period, whichever is
561 * higher.
562 */
563 public Builder setPeriodic(long intervalMillis, long flexMillis) {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700564 mIsPeriodic = true;
565 mIntervalMillis = intervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000566 mFlexMillis = flexMillis;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700567 mHasEarlyConstraint = mHasLateConstraint = true;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700568 return this;
569 }
570
571 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700572 * Specify that this job should be delayed by the provided amount of time.
573 * Because it doesn't make sense setting this property on a periodic job, doing so will
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700574 * throw an {@link java.lang.IllegalArgumentException} when
Christopher Tate7060b042014-06-09 19:50:00 -0700575 * {@link android.app.job.JobInfo.Builder#build()} is called.
576 * @param minLatencyMillis Milliseconds before which this job will not be considered for
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700577 * execution.
578 */
579 public Builder setMinimumLatency(long minLatencyMillis) {
580 mMinLatencyMillis = minLatencyMillis;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700581 mHasEarlyConstraint = true;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700582 return this;
583 }
584
585 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700586 * Set deadline which is the maximum scheduling latency. The job will be run by this
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700587 * deadline even if other requirements are not met. Because it doesn't make sense setting
Christopher Tate7060b042014-06-09 19:50:00 -0700588 * this property on a periodic job, doing so will throw an
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700589 * {@link java.lang.IllegalArgumentException} when
Christopher Tate7060b042014-06-09 19:50:00 -0700590 * {@link android.app.job.JobInfo.Builder#build()} is called.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700591 */
592 public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
593 mMaxExecutionDelayMillis = maxExecutionDelayMillis;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700594 mHasLateConstraint = true;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700595 return this;
596 }
597
598 /**
599 * Set up the back-off/retry policy.
Matthew Williamsd1c06752014-08-22 14:15:28 -0700600 * This defaults to some respectable values: {30 seconds, Exponential}. We cap back-off at
601 * 5hrs.
Christopher Tate7060b042014-06-09 19:50:00 -0700602 * Note that trying to set a backoff criteria for a job with
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700603 * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
Christopher Tate7060b042014-06-09 19:50:00 -0700604 * This is because back-off typically does not make sense for these types of jobs. See
605 * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
606 * for more description of the return value for the case of a job executing while in idle
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700607 * mode.
Christopher Tate7060b042014-06-09 19:50:00 -0700608 * @param initialBackoffMillis Millisecond time interval to wait initially when job has
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700609 * failed.
Matthew Williamsd1c06752014-08-22 14:15:28 -0700610 * @param backoffPolicy is one of {@link #BACKOFF_POLICY_LINEAR} or
611 * {@link #BACKOFF_POLICY_EXPONENTIAL}
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700612 */
613 public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) {
614 mBackoffPolicySet = true;
615 mInitialBackoffMillis = initialBackoffMillis;
616 mBackoffPolicy = backoffPolicy;
617 return this;
618 }
619
620 /**
Matthew Williams900c67f2014-07-09 12:46:53 -0700621 * Set whether or not to persist this job across device reboots. This will only have an
622 * effect if your application holds the permission
623 * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED}. Otherwise an exception will
624 * be thrown.
625 * @param isPersisted True to indicate that the job will be written to disk and loaded at
626 * boot.
627 */
Matthew Williamsd1c06752014-08-22 14:15:28 -0700628 public Builder setPersisted(boolean isPersisted) {
Matthew Williams900c67f2014-07-09 12:46:53 -0700629 mIsPersisted = isPersisted;
630 return this;
631 }
632
633 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700634 * @return The job object to hand to the JobScheduler. This object is immutable.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700635 */
Christopher Tate7060b042014-06-09 19:50:00 -0700636 public JobInfo build() {
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700637 // Allow jobs with no constraints - What am I, a database?
Matthew Williamsbafeeb92014-08-08 11:51:06 -0700638 if (!mHasEarlyConstraint && !mHasLateConstraint && !mRequiresCharging &&
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800639 !mRequiresDeviceIdle && mNetworkType == NETWORK_TYPE_NONE &&
640 mTriggerContentUris == null) {
Matthew Williamsbafeeb92014-08-08 11:51:06 -0700641 throw new IllegalArgumentException("You're trying to build a job with no " +
642 "constraints, this is not allowed.");
643 }
Matthew Williams3d86fd22014-05-16 18:02:17 -0700644 mExtras = new PersistableBundle(mExtras); // Make our own copy.
Christopher Tate7060b042014-06-09 19:50:00 -0700645 // Check that a deadline was not set on a periodic job.
Matthew Williams3d86fd22014-05-16 18:02:17 -0700646 if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700647 throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
Christopher Tate7060b042014-06-09 19:50:00 -0700648 "periodic job.");
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700649 }
Matthew Williams3d86fd22014-05-16 18:02:17 -0700650 if (mIsPeriodic && (mMinLatencyMillis != 0L)) {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700651 throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
Christopher Tate7060b042014-06-09 19:50:00 -0700652 "periodic job");
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700653 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800654 if (mIsPeriodic && (mTriggerContentUris != null)) {
655 throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +
656 "periodic job");
657 }
658 if (mIsPersisted && (mTriggerContentUris != null)) {
659 throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +
660 "persisted job");
661 }
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700662 if (mBackoffPolicySet && mRequiresDeviceIdle) {
Christopher Tate7060b042014-06-09 19:50:00 -0700663 throw new IllegalArgumentException("An idle mode job will not respect any" +
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700664 " back-off policy, so calling setBackoffCriteria with" +
665 " setRequiresDeviceIdle is an error.");
666 }
Shreyas Basargee96c3b72016-01-29 19:25:51 +0000667 JobInfo job = new JobInfo(this);
668 if (job.intervalMillis != job.getIntervalMillis()) {
Shreyas Basarged8bf6b92016-02-02 23:45:14 +0000669 Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is "
670 + formatForLogging(mIntervalMillis) + ". Clamped to " +
671 formatForLogging(job.getIntervalMillis()));
Shreyas Basargee96c3b72016-01-29 19:25:51 +0000672 }
673 if (job.flexMillis != job.getFlexMillis()) {
Shreyas Basarged8bf6b92016-02-02 23:45:14 +0000674 Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is "
675 + formatForLogging(mFlexMillis) + ". Clamped to " +
676 formatForLogging(job.getFlexMillis()));
Shreyas Basargee96c3b72016-01-29 19:25:51 +0000677 }
678 return job;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700679 }
680 }
681
682}