blob: 039c9d7c3c31cccbb89eb3ca2529925352643c52 [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 /**
Dianne Hackborn970510b2016-02-24 16:56:42 -0800105 * Value of {@link #getPriority} for a foreground app (overrides the supplied
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800106 * JobInfo priority if it is smaller).
107 * @hide
108 */
109 public static final int PRIORITY_FOREGROUND_APP = 30;
110
Dianne Hackborn970510b2016-02-24 16:56:42 -0800111 /**
112 * Value of {@link #getPriority} for the current top app (overrides the supplied
113 * JobInfo priority if it is smaller).
114 * @hide
115 */
116 public static final int PRIORITY_TOP_APP = 40;
117
Christopher Tate7060b042014-06-09 19:50:00 -0700118 private final int jobId;
Matthew Williams3d86fd22014-05-16 18:02:17 -0700119 private final PersistableBundle extras;
Matthew Williams6de79e22014-05-01 10:47:00 -0700120 private final ComponentName service;
121 private final boolean requireCharging;
122 private final boolean requireDeviceIdle;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800123 private final TriggerContentUri[] triggerContentUris;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700124 private final boolean hasEarlyConstraint;
125 private final boolean hasLateConstraint;
Matthew Williamsd1c06752014-08-22 14:15:28 -0700126 private final int networkType;
Matthew Williams6de79e22014-05-01 10:47:00 -0700127 private final long minLatencyMillis;
128 private final long maxExecutionDelayMillis;
129 private final boolean isPeriodic;
Matthew Williams900c67f2014-07-09 12:46:53 -0700130 private final boolean isPersisted;
Matthew Williams6de79e22014-05-01 10:47:00 -0700131 private final long intervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000132 private final long flexMillis;
Matthew Williams6de79e22014-05-01 10:47:00 -0700133 private final long initialBackoffMillis;
134 private final int backoffPolicy;
Shreyas Basarge5db09082016-01-07 13:38:29 +0000135 private final int priority;
Matthew Williams6de79e22014-05-01 10:47:00 -0700136
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700137 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700138 * Unique job id associated with this class. This is assigned to your job by the scheduler.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700139 */
Matthew Williams9b9244b62014-05-14 11:06:04 -0700140 public int getId() {
Christopher Tate7060b042014-06-09 19:50:00 -0700141 return jobId;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700142 }
143
144 /**
145 * Bundle of extras which are returned to your application at execution time.
146 */
Matthew Williams3d86fd22014-05-16 18:02:17 -0700147 public PersistableBundle getExtras() {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700148 return extras;
149 }
150
151 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700152 * Name of the service endpoint that will be called back into by the JobScheduler.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700153 */
Matthew Williams6de79e22014-05-01 10:47:00 -0700154 public ComponentName getService() {
155 return service;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700156 }
157
Shreyas Basarge5db09082016-01-07 13:38:29 +0000158 /** @hide */
159 public int getPriority() {
160 return priority;
161 }
162
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700163 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700164 * Whether this job needs the device to be plugged in.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700165 */
166 public boolean isRequireCharging() {
167 return requireCharging;
168 }
169
170 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700171 * Whether this job needs the device to be in an Idle maintenance window.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700172 */
173 public boolean isRequireDeviceIdle() {
174 return requireDeviceIdle;
175 }
176
177 /**
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800178 * Which content: URIs must change for the job to be scheduled. Returns null
179 * if there are none required.
180 */
181 @Nullable
182 public TriggerContentUri[] getTriggerContentUris() {
183 return triggerContentUris;
184 }
185
186 /**
Matthew Williamsd1c06752014-08-22 14:15:28 -0700187 * One of {@link android.app.job.JobInfo#NETWORK_TYPE_ANY},
188 * {@link android.app.job.JobInfo#NETWORK_TYPE_NONE}, or
189 * {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700190 */
Matthew Williamsd1c06752014-08-22 14:15:28 -0700191 public int getNetworkType() {
192 return networkType;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700193 }
194
195 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700196 * Set for a job that does not recur periodically, to specify a delay after which the job
197 * will be eligible for execution. This value is not set if the job recurs periodically.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700198 */
199 public long getMinLatencyMillis() {
200 return minLatencyMillis;
201 }
202
203 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700204 * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the job recurs
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700205 * periodically.
206 */
207 public long getMaxExecutionDelayMillis() {
208 return maxExecutionDelayMillis;
209 }
210
211 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700212 * Track whether this job will repeat with a given period.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700213 */
214 public boolean isPeriodic() {
215 return isPeriodic;
216 }
217
218 /**
Matthew Williams900c67f2014-07-09 12:46:53 -0700219 * @return Whether or not this job should be persisted across device reboots.
220 */
221 public boolean isPersisted() {
222 return isPersisted;
223 }
224
225 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700226 * Set to the interval between occurrences of this job. This value is <b>not</b> set if the
227 * job does not recur periodically.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700228 */
229 public long getIntervalMillis() {
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000230 return intervalMillis >= MIN_PERIOD_MILLIS ? intervalMillis : MIN_PERIOD_MILLIS;
231 }
232
233 /**
234 * Flex time for this job. Only valid if this is a periodic job.
235 */
236 public long getFlexMillis() {
237 long interval = getIntervalMillis();
238 long percentClamp = 5 * interval / 100;
239 long clampedFlex = Math.max(flexMillis, Math.max(percentClamp, MIN_FLEX_MILLIS));
240 return clampedFlex <= interval ? clampedFlex : interval;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700241 }
242
243 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700244 * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
245 * will be increased depending on the backoff policy specified at job creation time. Defaults
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700246 * to 5 seconds.
247 */
248 public long getInitialBackoffMillis() {
249 return initialBackoffMillis;
250 }
251
252 /**
Matthew Williamsd1c06752014-08-22 14:15:28 -0700253 * One of either {@link android.app.job.JobInfo#BACKOFF_POLICY_EXPONENTIAL}, or
254 * {@link android.app.job.JobInfo#BACKOFF_POLICY_LINEAR}, depending on which criteria you set
255 * when creating this job.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700256 */
257 public int getBackoffPolicy() {
258 return backoffPolicy;
259 }
260
Matthew Williams9b9244b62014-05-14 11:06:04 -0700261 /**
262 * User can specify an early constraint of 0L, which is valid, so we keep track of whether the
263 * function was called at all.
264 * @hide
265 */
266 public boolean hasEarlyConstraint() {
267 return hasEarlyConstraint;
268 }
269
270 /**
271 * User can specify a late constraint of 0L, which is valid, so we keep track of whether the
272 * function was called at all.
273 * @hide
274 */
275 public boolean hasLateConstraint() {
276 return hasLateConstraint;
277 }
278
Christopher Tate7060b042014-06-09 19:50:00 -0700279 private JobInfo(Parcel in) {
280 jobId = in.readInt();
Matthew Williams3d86fd22014-05-16 18:02:17 -0700281 extras = in.readPersistableBundle();
Matthew Williamseffacfa2014-06-05 20:56:40 -0700282 service = in.readParcelable(null);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700283 requireCharging = in.readInt() == 1;
284 requireDeviceIdle = in.readInt() == 1;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800285 triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR);
Matthew Williamsd1c06752014-08-22 14:15:28 -0700286 networkType = in.readInt();
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700287 minLatencyMillis = in.readLong();
288 maxExecutionDelayMillis = in.readLong();
289 isPeriodic = in.readInt() == 1;
Matthew Williams900c67f2014-07-09 12:46:53 -0700290 isPersisted = in.readInt() == 1;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700291 intervalMillis = in.readLong();
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000292 flexMillis = in.readLong();
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700293 initialBackoffMillis = in.readLong();
294 backoffPolicy = in.readInt();
Matthew Williams9b9244b62014-05-14 11:06:04 -0700295 hasEarlyConstraint = in.readInt() == 1;
296 hasLateConstraint = in.readInt() == 1;
Shreyas Basarge5db09082016-01-07 13:38:29 +0000297 priority = in.readInt();
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700298 }
299
Christopher Tate7060b042014-06-09 19:50:00 -0700300 private JobInfo(JobInfo.Builder b) {
301 jobId = b.mJobId;
Matthew Williamseffacfa2014-06-05 20:56:40 -0700302 extras = b.mExtras;
Christopher Tate7060b042014-06-09 19:50:00 -0700303 service = b.mJobService;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700304 requireCharging = b.mRequiresCharging;
305 requireDeviceIdle = b.mRequiresDeviceIdle;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800306 triggerContentUris = b.mTriggerContentUris != null
307 ? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()])
308 : null;
Matthew Williamsd1c06752014-08-22 14:15:28 -0700309 networkType = b.mNetworkType;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700310 minLatencyMillis = b.mMinLatencyMillis;
311 maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
312 isPeriodic = b.mIsPeriodic;
Matthew Williams900c67f2014-07-09 12:46:53 -0700313 isPersisted = b.mIsPersisted;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700314 intervalMillis = b.mIntervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000315 flexMillis = b.mFlexMillis;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700316 initialBackoffMillis = b.mInitialBackoffMillis;
317 backoffPolicy = b.mBackoffPolicy;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700318 hasEarlyConstraint = b.mHasEarlyConstraint;
319 hasLateConstraint = b.mHasLateConstraint;
Shreyas Basarge5db09082016-01-07 13:38:29 +0000320 priority = b.mPriority;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700321 }
322
323 @Override
324 public int describeContents() {
325 return 0;
326 }
327
328 @Override
329 public void writeToParcel(Parcel out, int flags) {
Christopher Tate7060b042014-06-09 19:50:00 -0700330 out.writeInt(jobId);
Matthew Williams3d86fd22014-05-16 18:02:17 -0700331 out.writePersistableBundle(extras);
Matthew Williamseffacfa2014-06-05 20:56:40 -0700332 out.writeParcelable(service, flags);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700333 out.writeInt(requireCharging ? 1 : 0);
334 out.writeInt(requireDeviceIdle ? 1 : 0);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800335 out.writeTypedArray(triggerContentUris, flags);
Matthew Williamsd1c06752014-08-22 14:15:28 -0700336 out.writeInt(networkType);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700337 out.writeLong(minLatencyMillis);
338 out.writeLong(maxExecutionDelayMillis);
339 out.writeInt(isPeriodic ? 1 : 0);
Matthew Williams900c67f2014-07-09 12:46:53 -0700340 out.writeInt(isPersisted ? 1 : 0);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700341 out.writeLong(intervalMillis);
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000342 out.writeLong(flexMillis);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700343 out.writeLong(initialBackoffMillis);
344 out.writeInt(backoffPolicy);
Matthew Williams9b9244b62014-05-14 11:06:04 -0700345 out.writeInt(hasEarlyConstraint ? 1 : 0);
346 out.writeInt(hasLateConstraint ? 1 : 0);
Shreyas Basarge5db09082016-01-07 13:38:29 +0000347 out.writeInt(priority);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700348 }
349
Christopher Tate7060b042014-06-09 19:50:00 -0700350 public static final Creator<JobInfo> CREATOR = new Creator<JobInfo>() {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700351 @Override
Christopher Tate7060b042014-06-09 19:50:00 -0700352 public JobInfo createFromParcel(Parcel in) {
353 return new JobInfo(in);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700354 }
355
356 @Override
Christopher Tate7060b042014-06-09 19:50:00 -0700357 public JobInfo[] newArray(int size) {
358 return new JobInfo[size];
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700359 }
360 };
361
Matthew Williamsee410da2014-07-25 11:30:40 -0700362 @Override
363 public String toString() {
364 return "(job:" + jobId + "/" + service.flattenToShortString() + ")";
365 }
366
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800367 /**
368 * Information about a content URI modification that a job would like to
369 * trigger on.
370 */
371 public static final class TriggerContentUri implements Parcelable {
372 private final Uri mUri;
373 private final int mFlags;
374
375 /**
376 * Flag for trigger: also trigger if any descendants of the given URI change.
377 * Corresponds to the <var>notifyForDescendants</var> of
378 * {@link android.content.ContentResolver#registerContentObserver}.
379 */
380 public static final int FLAG_NOTIFY_FOR_DESCENDANTS = 1<<0;
381
382 /**
383 * Create a new trigger description.
384 * @param uri The URI to observe. Must be non-null.
385 * @param flags Optional flags for the observer, either 0 or
386 * {@link #FLAG_NOTIFY_FOR_DESCENDANTS}.
387 */
388 public TriggerContentUri(@NonNull Uri uri, int flags) {
389 mUri = uri;
390 mFlags = flags;
391 }
392
393 /**
394 * Return the Uri this trigger was created for.
395 */
396 public Uri getUri() {
397 return mUri;
398 }
399
400 /**
401 * Return the flags supplied for the trigger.
402 */
403 public int getFlags() {
404 return mFlags;
405 }
406
407 private TriggerContentUri(Parcel in) {
408 mUri = Uri.CREATOR.createFromParcel(in);
409 mFlags = in.readInt();
410 }
411
412 @Override
413 public int describeContents() {
414 return 0;
415 }
416
417 @Override
418 public void writeToParcel(Parcel out, int flags) {
419 mUri.writeToParcel(out, flags);
420 out.writeInt(mFlags);
421 }
422
423 public static final Creator<TriggerContentUri> CREATOR = new Creator<TriggerContentUri>() {
424 @Override
425 public TriggerContentUri createFromParcel(Parcel in) {
426 return new TriggerContentUri(in);
427 }
428
429 @Override
430 public TriggerContentUri[] newArray(int size) {
431 return new TriggerContentUri[size];
432 }
433 };
434 }
435
Christopher Tate7060b042014-06-09 19:50:00 -0700436 /** Builder class for constructing {@link JobInfo} objects. */
Matthew Williams9b9244b62014-05-14 11:06:04 -0700437 public static final class Builder {
Christopher Tate7060b042014-06-09 19:50:00 -0700438 private int mJobId;
Matthew Williams3d86fd22014-05-16 18:02:17 -0700439 private PersistableBundle mExtras = PersistableBundle.EMPTY;
Christopher Tate7060b042014-06-09 19:50:00 -0700440 private ComponentName mJobService;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800441 private int mPriority = PRIORITY_DEFAULT;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700442 // Requirements.
443 private boolean mRequiresCharging;
444 private boolean mRequiresDeviceIdle;
Matthew Williamsd1c06752014-08-22 14:15:28 -0700445 private int mNetworkType;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800446 private ArrayList<TriggerContentUri> mTriggerContentUris;
Matthew Williams900c67f2014-07-09 12:46:53 -0700447 private boolean mIsPersisted;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700448 // One-off parameters.
449 private long mMinLatencyMillis;
450 private long mMaxExecutionDelayMillis;
451 // Periodic parameters.
452 private boolean mIsPeriodic;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700453 private boolean mHasEarlyConstraint;
454 private boolean mHasLateConstraint;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700455 private long mIntervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000456 private long mFlexMillis;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700457 // Back-off parameters.
Matthew Williams3d86fd22014-05-16 18:02:17 -0700458 private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS;
459 private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700460 /** Easy way to track whether the client has tried to set a back-off policy. */
461 private boolean mBackoffPolicySet = false;
462
463 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700464 * @param jobId Application-provided id for this job. Subsequent calls to cancel, or
465 * jobs created with the same jobId, will update the pre-existing job with
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700466 * the same id.
Christopher Tate7060b042014-06-09 19:50:00 -0700467 * @param jobService The endpoint that you implement that will receive the callback from the
468 * JobScheduler.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700469 */
Christopher Tate7060b042014-06-09 19:50:00 -0700470 public Builder(int jobId, ComponentName jobService) {
471 mJobService = jobService;
472 mJobId = jobId;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700473 }
474
475 /**
Shreyas Basarge5db09082016-01-07 13:38:29 +0000476 * @hide
477 */
478 public Builder setPriority(int priority) {
479 mPriority = priority;
480 return this;
481 }
482
483 /**
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700484 * Set optional extras. This is persisted, so we only allow primitive types.
485 * @param extras Bundle containing extras you want the scheduler to hold on to for you.
486 */
Matthew Williams3d86fd22014-05-16 18:02:17 -0700487 public Builder setExtras(PersistableBundle extras) {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700488 mExtras = extras;
489 return this;
490 }
491
492 /**
Matthew Williamsd1c06752014-08-22 14:15:28 -0700493 * Set some description of the kind of network type your job needs to have.
494 * Not calling this function means the network is not necessary, as the default is
495 * {@link #NETWORK_TYPE_NONE}.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700496 * Bear in mind that calling this function defines network as a strict requirement for your
Matthew Williamsd1c06752014-08-22 14:15:28 -0700497 * job. If the network requested is not available your job will never run. See
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700498 * {@link #setOverrideDeadline(long)} to change this behaviour.
499 */
Matthew Williamsd1c06752014-08-22 14:15:28 -0700500 public Builder setRequiredNetworkType(int networkType) {
501 mNetworkType = networkType;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700502 return this;
503 }
504
Christopher Tate7060b042014-06-09 19:50:00 -0700505 /**
506 * Specify that to run this job, the device needs to be plugged in. This defaults to
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700507 * false.
Christopher Tate7060b042014-06-09 19:50:00 -0700508 * @param requiresCharging Whether or not the device is plugged in.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700509 */
510 public Builder setRequiresCharging(boolean requiresCharging) {
511 mRequiresCharging = requiresCharging;
512 return this;
513 }
514
515 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700516 * Specify that to run, the job needs the device to be in idle mode. This defaults to
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700517 * false.
518 * <p>Idle mode is a loose definition provided by the system, which means that the device
519 * 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 -0700520 * perform resource heavy jobs. Bear in mind that battery usage will still be attributed
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700521 * to your application, and surfaced to the user in battery stats.</p>
522 * @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
523 * window.
524 */
525 public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
526 mRequiresDeviceIdle = requiresDeviceIdle;
527 return this;
528 }
529
530 /**
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800531 * Add a new content: URI that will be monitored with a
532 * {@link android.database.ContentObserver}, and will cause the job to execute if changed.
533 * If you have any trigger content URIs associated with a job, it will not execute until
534 * there has been a change report for one or more of them.
535 * <p>Note that trigger URIs can not be used in combination with
536 * {@link #setPeriodic(long)} or {@link #setPersisted(boolean)}. To continually monitor
537 * for content changes, you need to schedule a new JobInfo observing the same URIs
538 * before you finish execution of the JobService handling the most recent changes.</p>
539 * @param uri The content: URI to monitor.
540 */
541 public Builder addTriggerContentUri(@NonNull TriggerContentUri uri) {
542 if (mTriggerContentUris == null) {
543 mTriggerContentUris = new ArrayList<>();
544 }
545 mTriggerContentUris.add(uri);
546 return this;
547 }
548
549 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700550 * Specify that this job should recur with the provided interval, not more than once per
551 * period. You have no control over when within this interval this job will be executed,
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700552 * only the guarantee that it will be executed at most once within this interval.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700553 * Setting this function on the builder with {@link #setMinimumLatency(long)} or
554 * {@link #setOverrideDeadline(long)} will result in an error.
Christopher Tate7060b042014-06-09 19:50:00 -0700555 * @param intervalMillis Millisecond interval for which this job will repeat.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700556 */
557 public Builder setPeriodic(long intervalMillis) {
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000558 return setPeriodic(intervalMillis, intervalMillis);
559 }
560
561 /**
562 * Specify that this job should recur with the provided interval and flex. The job can
563 * execute at any time in a window of flex length at the end of the period.
Shreyas Basargee96c3b72016-01-29 19:25:51 +0000564 * @param intervalMillis Millisecond interval for which this job will repeat. A minimum
565 * value of {@link #MIN_PERIOD_MILLIS} is enforced.
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000566 * @param flexMillis Millisecond flex for this job. Flex is clamped to be at least
567 * {@link #MIN_FLEX_MILLIS} or 5 percent of the period, whichever is
568 * higher.
569 */
570 public Builder setPeriodic(long intervalMillis, long flexMillis) {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700571 mIsPeriodic = true;
572 mIntervalMillis = intervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000573 mFlexMillis = flexMillis;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700574 mHasEarlyConstraint = mHasLateConstraint = true;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700575 return this;
576 }
577
578 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700579 * Specify that this job should be delayed by the provided amount of time.
580 * Because it doesn't make sense setting this property on a periodic job, doing so will
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700581 * throw an {@link java.lang.IllegalArgumentException} when
Christopher Tate7060b042014-06-09 19:50:00 -0700582 * {@link android.app.job.JobInfo.Builder#build()} is called.
583 * @param minLatencyMillis Milliseconds before which this job will not be considered for
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700584 * execution.
585 */
586 public Builder setMinimumLatency(long minLatencyMillis) {
587 mMinLatencyMillis = minLatencyMillis;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700588 mHasEarlyConstraint = true;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700589 return this;
590 }
591
592 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700593 * Set deadline which is the maximum scheduling latency. The job will be run by this
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700594 * deadline even if other requirements are not met. Because it doesn't make sense setting
Christopher Tate7060b042014-06-09 19:50:00 -0700595 * this property on a periodic job, doing so will throw an
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700596 * {@link java.lang.IllegalArgumentException} when
Christopher Tate7060b042014-06-09 19:50:00 -0700597 * {@link android.app.job.JobInfo.Builder#build()} is called.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700598 */
599 public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
600 mMaxExecutionDelayMillis = maxExecutionDelayMillis;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700601 mHasLateConstraint = true;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700602 return this;
603 }
604
605 /**
606 * Set up the back-off/retry policy.
Matthew Williamsd1c06752014-08-22 14:15:28 -0700607 * This defaults to some respectable values: {30 seconds, Exponential}. We cap back-off at
608 * 5hrs.
Christopher Tate7060b042014-06-09 19:50:00 -0700609 * Note that trying to set a backoff criteria for a job with
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700610 * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
Christopher Tate7060b042014-06-09 19:50:00 -0700611 * This is because back-off typically does not make sense for these types of jobs. See
612 * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
613 * for more description of the return value for the case of a job executing while in idle
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700614 * mode.
Christopher Tate7060b042014-06-09 19:50:00 -0700615 * @param initialBackoffMillis Millisecond time interval to wait initially when job has
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700616 * failed.
Matthew Williamsd1c06752014-08-22 14:15:28 -0700617 * @param backoffPolicy is one of {@link #BACKOFF_POLICY_LINEAR} or
618 * {@link #BACKOFF_POLICY_EXPONENTIAL}
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700619 */
620 public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) {
621 mBackoffPolicySet = true;
622 mInitialBackoffMillis = initialBackoffMillis;
623 mBackoffPolicy = backoffPolicy;
624 return this;
625 }
626
627 /**
Matthew Williams900c67f2014-07-09 12:46:53 -0700628 * Set whether or not to persist this job across device reboots. This will only have an
629 * effect if your application holds the permission
630 * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED}. Otherwise an exception will
631 * be thrown.
632 * @param isPersisted True to indicate that the job will be written to disk and loaded at
633 * boot.
634 */
Matthew Williamsd1c06752014-08-22 14:15:28 -0700635 public Builder setPersisted(boolean isPersisted) {
Matthew Williams900c67f2014-07-09 12:46:53 -0700636 mIsPersisted = isPersisted;
637 return this;
638 }
639
640 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700641 * @return The job object to hand to the JobScheduler. This object is immutable.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700642 */
Christopher Tate7060b042014-06-09 19:50:00 -0700643 public JobInfo build() {
Matthew Williams9ae3dbe2014-08-21 13:47:47 -0700644 // Allow jobs with no constraints - What am I, a database?
Matthew Williamsbafeeb92014-08-08 11:51:06 -0700645 if (!mHasEarlyConstraint && !mHasLateConstraint && !mRequiresCharging &&
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800646 !mRequiresDeviceIdle && mNetworkType == NETWORK_TYPE_NONE &&
647 mTriggerContentUris == null) {
Matthew Williamsbafeeb92014-08-08 11:51:06 -0700648 throw new IllegalArgumentException("You're trying to build a job with no " +
649 "constraints, this is not allowed.");
650 }
Matthew Williams3d86fd22014-05-16 18:02:17 -0700651 mExtras = new PersistableBundle(mExtras); // Make our own copy.
Christopher Tate7060b042014-06-09 19:50:00 -0700652 // Check that a deadline was not set on a periodic job.
Matthew Williams3d86fd22014-05-16 18:02:17 -0700653 if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700654 throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
Christopher Tate7060b042014-06-09 19:50:00 -0700655 "periodic job.");
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700656 }
Matthew Williams3d86fd22014-05-16 18:02:17 -0700657 if (mIsPeriodic && (mMinLatencyMillis != 0L)) {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700658 throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
Christopher Tate7060b042014-06-09 19:50:00 -0700659 "periodic job");
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700660 }
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800661 if (mIsPeriodic && (mTriggerContentUris != null)) {
662 throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +
663 "periodic job");
664 }
665 if (mIsPersisted && (mTriggerContentUris != null)) {
666 throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +
667 "persisted job");
668 }
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700669 if (mBackoffPolicySet && mRequiresDeviceIdle) {
Christopher Tate7060b042014-06-09 19:50:00 -0700670 throw new IllegalArgumentException("An idle mode job will not respect any" +
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700671 " back-off policy, so calling setBackoffCriteria with" +
672 " setRequiresDeviceIdle is an error.");
673 }
Shreyas Basargee96c3b72016-01-29 19:25:51 +0000674 JobInfo job = new JobInfo(this);
675 if (job.intervalMillis != job.getIntervalMillis()) {
Shreyas Basarged8bf6b92016-02-02 23:45:14 +0000676 Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is "
677 + formatForLogging(mIntervalMillis) + ". Clamped to " +
678 formatForLogging(job.getIntervalMillis()));
Shreyas Basargee96c3b72016-01-29 19:25:51 +0000679 }
680 if (job.flexMillis != job.getFlexMillis()) {
Shreyas Basarged8bf6b92016-02-02 23:45:14 +0000681 Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is "
682 + formatForLogging(mFlexMillis) + ". Clamped to " +
683 formatForLogging(job.getFlexMillis()));
Shreyas Basargee96c3b72016-01-29 19:25:51 +0000684 }
685 return job;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700686 }
687 }
688
689}