blob: 02afcc7cf70677ef0cdf46ad4d9bfbe8d9659211 [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
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -070019import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
20import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
21import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
22import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
23import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
24import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
Jeff Sharkey1b6519b2016-04-28 15:33:18 -060025import static android.util.TimeUtils.formatDuration;
26
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -060027import android.annotation.BytesLong;
Jeff Sharkey30e06bb2017-04-24 11:18:03 -060028import android.annotation.IntDef;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080029import android.annotation.NonNull;
30import android.annotation.Nullable;
Jeff Sharkey30e06bb2017-04-24 11:18:03 -060031import android.annotation.RequiresPermission;
Dianne Hackborna47223f2017-03-30 13:49:13 -070032import android.content.ClipData;
Christopher Tatefa380e92014-05-19 13:46:29 -070033import android.content.ComponentName;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -070034import android.net.NetworkRequest;
35import android.net.NetworkSpecifier;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080036import android.net.Uri;
Dianne Hackborn7da13d72017-04-04 17:17:35 -070037import android.os.BaseBundle;
Dianne Hackbornba604732016-02-10 17:05:10 -080038import android.os.Bundle;
Matthew Williams6e31c5c2014-04-11 15:49:16 -070039import android.os.Parcel;
40import android.os.Parcelable;
Matthew Williams3d86fd22014-05-16 18:02:17 -070041import android.os.PersistableBundle;
Shreyas Basargee96c3b72016-01-29 19:25:51 +000042import android.util.Log;
Matthew Williams6e31c5c2014-04-11 15:49:16 -070043
Jeff Sharkey30e06bb2017-04-24 11:18:03 -060044import java.lang.annotation.Retention;
45import java.lang.annotation.RetentionPolicy;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080046import java.util.ArrayList;
Paul Duffinc67663c2017-05-26 09:46:48 +010047import java.util.Arrays;
Dianne Hackborn121e1642016-06-21 20:39:02 -070048import java.util.Objects;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080049
Matthew Williams6e31c5c2014-04-11 15:49:16 -070050/**
Christopher Tate7060b042014-06-09 19:50:00 -070051 * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
Matthew Williams6e31c5c2014-04-11 15:49:16 -070052 * parameters required to schedule work against the calling application. These are constructed
Christopher Tate7060b042014-06-09 19:50:00 -070053 * using the {@link JobInfo.Builder}.
Matthew Williams9ae3dbe2014-08-21 13:47:47 -070054 * You must specify at least one sort of constraint on the JobInfo object that you are creating.
55 * The goal here is to provide the scheduler with high-level semantics about the work you want to
56 * accomplish. Doing otherwise with throw an exception in your app.
Matthew Williams6e31c5c2014-04-11 15:49:16 -070057 */
Christopher Tate7060b042014-06-09 19:50:00 -070058public class JobInfo implements Parcelable {
Shreyas Basargee96c3b72016-01-29 19:25:51 +000059 private static String TAG = "JobInfo";
Jeff Sharkey30e06bb2017-04-24 11:18:03 -060060
61 /** @hide */
62 @IntDef(prefix = { "NETWORK_TYPE_" }, value = {
63 NETWORK_TYPE_NONE,
64 NETWORK_TYPE_ANY,
65 NETWORK_TYPE_UNMETERED,
66 NETWORK_TYPE_NOT_ROAMING,
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -070067 NETWORK_TYPE_CELLULAR,
Jeff Sharkey30e06bb2017-04-24 11:18:03 -060068 })
69 @Retention(RetentionPolicy.SOURCE)
70 public @interface NetworkType {}
71
Matthew Williamsd1c06752014-08-22 14:15:28 -070072 /** Default. */
73 public static final int NETWORK_TYPE_NONE = 0;
74 /** This job requires network connectivity. */
75 public static final int NETWORK_TYPE_ANY = 1;
76 /** This job requires network connectivity that is unmetered. */
77 public static final int NETWORK_TYPE_UNMETERED = 2;
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -060078 /** This job requires network connectivity that is not roaming. */
79 public static final int NETWORK_TYPE_NOT_ROAMING = 3;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -070080 /** This job requires network connectivity that is a cellular network. */
81 public static final int NETWORK_TYPE_CELLULAR = 4;
82
83 /**
84 * This job requires metered connectivity such as most cellular data
85 * networks.
86 *
87 * @deprecated Cellular networks may be unmetered, or Wi-Fi networks may be
88 * metered, so this isn't a good way of selecting a specific
89 * transport. Instead, use {@link #NETWORK_TYPE_CELLULAR} or
90 * {@link android.net.NetworkRequest.Builder#addTransportType(int)}
91 * if your job requires a specific network transport.
92 */
93 @Deprecated
94 public static final int NETWORK_TYPE_METERED = NETWORK_TYPE_CELLULAR;
Matthew Williams6e31c5c2014-04-11 15:49:16 -070095
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -060096 /** Sentinel value indicating that bytes are unknown. */
97 public static final int NETWORK_BYTES_UNKNOWN = -1;
98
Matthew Williams6e31c5c2014-04-11 15:49:16 -070099 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700100 * Amount of backoff a job has initially by default, in milliseconds.
Matthew Williams3d86fd22014-05-16 18:02:17 -0700101 */
Matthew Williamsd1c06752014-08-22 14:15:28 -0700102 public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 30 seconds.
103
104 /**
105 * Maximum backoff we allow for a job, in milliseconds.
106 */
107 public static final long MAX_BACKOFF_DELAY_MILLIS = 5 * 60 * 60 * 1000; // 5 hours.
108
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600109 /** @hide */
110 @IntDef(prefix = { "BACKOFF_POLICY_" }, value = {
111 BACKOFF_POLICY_LINEAR,
112 BACKOFF_POLICY_EXPONENTIAL,
113 })
114 @Retention(RetentionPolicy.SOURCE)
115 public @interface BackoffPolicy {}
116
Matthew Williamsd1c06752014-08-22 14:15:28 -0700117 /**
118 * Linearly back-off a failed job. See
119 * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}
120 * retry_time(current_time, num_failures) =
121 * current_time + initial_backoff_millis * num_failures, num_failures >= 1
122 */
123 public static final int BACKOFF_POLICY_LINEAR = 0;
124
125 /**
126 * Exponentially back-off a failed job. See
127 * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}
128 *
129 * retry_time(current_time, num_failures) =
130 * current_time + initial_backoff_millis * 2 ^ (num_failures - 1), num_failures >= 1
131 */
132 public static final int BACKOFF_POLICY_EXPONENTIAL = 1;
Matthew Williams3d86fd22014-05-16 18:02:17 -0700133
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000134 /* Minimum interval for a periodic job, in milliseconds. */
Christopher Tate10be4e92016-03-15 16:56:21 -0700135 private static final long MIN_PERIOD_MILLIS = 15 * 60 * 1000L; // 15 minutes
136
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000137 /* Minimum flex for a periodic job, in milliseconds. */
Christopher Tate10be4e92016-03-15 16:56:21 -0700138 private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
139
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700140 /**
141 * Minimum backoff interval for a job, in milliseconds
142 * @hide
143 */
144 public static final long MIN_BACKOFF_MILLIS = 10 * 1000L; // 10 seconds
Christopher Tateb2087f82017-03-29 17:42:39 -0700145
Christopher Tate10be4e92016-03-15 16:56:21 -0700146 /**
147 * Query the minimum interval allowed for periodic scheduled jobs. Attempting
148 * to declare a smaller period that this when scheduling a job will result in a
149 * job that is still periodic, but will run with this effective period.
150 *
151 * @return The minimum available interval for scheduling periodic jobs, in milliseconds.
152 */
Christopher Tatea9b4f3f2016-05-18 13:57:37 -0700153 public static final long getMinPeriodMillis() {
Christopher Tate10be4e92016-03-15 16:56:21 -0700154 return MIN_PERIOD_MILLIS;
155 }
156
157 /**
158 * Query the minimum flex time allowed for periodic scheduled jobs. Attempting
159 * to declare a shorter flex time than this when scheduling such a job will
160 * result in this amount as the effective flex time for the job.
161 *
162 * @return The minimum available flex time for scheduling periodic jobs, in milliseconds.
163 */
Christopher Tatea9b4f3f2016-05-18 13:57:37 -0700164 public static final long getMinFlexMillis() {
Christopher Tate10be4e92016-03-15 16:56:21 -0700165 return MIN_FLEX_MILLIS;
166 }
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000167
Matthew Williams3d86fd22014-05-16 18:02:17 -0700168 /**
Christopher Tateb2087f82017-03-29 17:42:39 -0700169 * Query the minimum automatic-reschedule backoff interval permitted for jobs.
170 * @hide
171 */
172 public static final long getMinBackoffMillis() {
173 return MIN_BACKOFF_MILLIS;
174 }
175
176 /**
Matthew Williams3d86fd22014-05-16 18:02:17 -0700177 * Default type of backoff.
178 * @hide
179 */
Matthew Williamsd1c06752014-08-22 14:15:28 -0700180 public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700181
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800182 /**
183 * Default of {@link #getPriority}.
184 * @hide
185 */
186 public static final int PRIORITY_DEFAULT = 0;
187
188 /**
189 * Value of {@link #getPriority} for expedited syncs.
190 * @hide
191 */
192 public static final int PRIORITY_SYNC_EXPEDITED = 10;
193
194 /**
195 * Value of {@link #getPriority} for first time initialization syncs.
196 * @hide
197 */
198 public static final int PRIORITY_SYNC_INITIALIZATION = 20;
199
200 /**
Dianne Hackborn970510b2016-02-24 16:56:42 -0800201 * Value of {@link #getPriority} for a foreground app (overrides the supplied
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800202 * JobInfo priority if it is smaller).
203 * @hide
204 */
205 public static final int PRIORITY_FOREGROUND_APP = 30;
206
Dianne Hackborn970510b2016-02-24 16:56:42 -0800207 /**
208 * Value of {@link #getPriority} for the current top app (overrides the supplied
209 * JobInfo priority if it is smaller).
210 * @hide
211 */
212 public static final int PRIORITY_TOP_APP = 40;
213
Dianne Hackborn807de782016-04-07 17:54:41 -0700214 /**
215 * Adjustment of {@link #getPriority} if the app has often (50% or more of the time)
216 * been running jobs.
217 * @hide
218 */
219 public static final int PRIORITY_ADJ_OFTEN_RUNNING = -40;
220
221 /**
222 * Adjustment of {@link #getPriority} if the app has always (90% or more of the time)
223 * been running jobs.
224 * @hide
225 */
226 public static final int PRIORITY_ADJ_ALWAYS_RUNNING = -80;
227
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600228 /**
229 * Indicates that the implementation of this job will be using
230 * {@link JobService#startForeground(int, android.app.Notification)} to run
231 * in the foreground.
232 * <p>
233 * When set, the internal scheduling of this job will ignore any background
234 * network restrictions for the requesting app. Note that this flag alone
235 * doesn't actually place your {@link JobService} in the foreground; you
236 * still need to post the notification yourself.
Jeff Sharkey785f4942016-07-14 10:31:15 -0600237 * <p>
238 * To use this flag, the caller must hold the
239 * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL} permission.
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600240 *
241 * @hide
242 */
243 public static final int FLAG_WILL_BE_FOREGROUND = 1 << 0;
244
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800245 /**
Suprabh Shukla106203b2017-11-02 21:23:44 -0700246 * Allows this job to run despite doze restrictions as long as the app is in the foreground
247 * or on the temporary whitelist
248 * @hide
249 */
250 public static final int FLAG_IMPORTANT_WHILE_FOREGROUND = 1 << 1;
251
252 /**
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800253 * @hide
254 */
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600255 public static final int FLAG_PREFETCH = 1 << 2;
Jeff Sharkey9252b342018-01-19 07:58:35 +0900256
257 /**
Makoto Onuki959acb52018-01-26 14:10:03 -0800258 * This job needs to be exempted from the app standby throttling. Only the system (UID 1000)
259 * can set it. Jobs with a time constrant must not have it.
260 *
261 * @hide
262 */
263 public static final int FLAG_EXEMPT_FROM_APP_STANDBY = 1 << 3;
264
265 /**
Jeff Sharkey9252b342018-01-19 07:58:35 +0900266 * @hide
267 */
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800268 public static final int CONSTRAINT_FLAG_CHARGING = 1 << 0;
269
270 /**
271 * @hide
272 */
273 public static final int CONSTRAINT_FLAG_BATTERY_NOT_LOW = 1 << 1;
274
275 /**
276 * @hide
277 */
278 public static final int CONSTRAINT_FLAG_DEVICE_IDLE = 1 << 2;
279
Dianne Hackborn532ea262017-03-17 17:50:55 -0700280 /**
281 * @hide
282 */
283 public static final int CONSTRAINT_FLAG_STORAGE_NOT_LOW = 1 << 3;
284
Christopher Tate7060b042014-06-09 19:50:00 -0700285 private final int jobId;
Matthew Williams3d86fd22014-05-16 18:02:17 -0700286 private final PersistableBundle extras;
Dianne Hackbornba604732016-02-10 17:05:10 -0800287 private final Bundle transientExtras;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700288 private final ClipData clipData;
289 private final int clipGrantFlags;
Matthew Williams6de79e22014-05-01 10:47:00 -0700290 private final ComponentName service;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800291 private final int constraintFlags;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800292 private final TriggerContentUri[] triggerContentUris;
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700293 private final long triggerContentUpdateDelay;
294 private final long triggerContentMaxDelay;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700295 private final boolean hasEarlyConstraint;
296 private final boolean hasLateConstraint;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700297 private final NetworkRequest networkRequest;
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600298 private final long networkDownloadBytes;
299 private final long networkUploadBytes;
Matthew Williams6de79e22014-05-01 10:47:00 -0700300 private final long minLatencyMillis;
301 private final long maxExecutionDelayMillis;
302 private final boolean isPeriodic;
Matthew Williams900c67f2014-07-09 12:46:53 -0700303 private final boolean isPersisted;
Matthew Williams6de79e22014-05-01 10:47:00 -0700304 private final long intervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000305 private final long flexMillis;
Matthew Williams6de79e22014-05-01 10:47:00 -0700306 private final long initialBackoffMillis;
307 private final int backoffPolicy;
Shreyas Basarge5db09082016-01-07 13:38:29 +0000308 private final int priority;
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600309 private final int flags;
Matthew Williams6de79e22014-05-01 10:47:00 -0700310
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700311 /**
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700312 * Unique job id associated with this application (uid). This is the same job ID
313 * you supplied in the {@link Builder} constructor.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700314 */
Matthew Williams9b9244b62014-05-14 11:06:04 -0700315 public int getId() {
Christopher Tate7060b042014-06-09 19:50:00 -0700316 return jobId;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700317 }
318
319 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600320 * @see JobInfo.Builder#setExtras(PersistableBundle)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700321 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700322 public @NonNull PersistableBundle getExtras() {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700323 return extras;
324 }
325
326 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600327 * @see JobInfo.Builder#setTransientExtras(Bundle)
Dianne Hackbornba604732016-02-10 17:05:10 -0800328 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700329 public @NonNull Bundle getTransientExtras() {
Dianne Hackbornba604732016-02-10 17:05:10 -0800330 return transientExtras;
331 }
332
333 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600334 * @see JobInfo.Builder#setClipData(ClipData, int)
Dianne Hackborna47223f2017-03-30 13:49:13 -0700335 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700336 public @Nullable ClipData getClipData() {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700337 return clipData;
338 }
339
340 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600341 * @see JobInfo.Builder#setClipData(ClipData, int)
Dianne Hackborna47223f2017-03-30 13:49:13 -0700342 */
343 public int getClipGrantFlags() {
344 return clipGrantFlags;
345 }
346
347 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700348 * Name of the service endpoint that will be called back into by the JobScheduler.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700349 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700350 public @NonNull ComponentName getService() {
Matthew Williams6de79e22014-05-01 10:47:00 -0700351 return service;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700352 }
353
Shreyas Basarge5db09082016-01-07 13:38:29 +0000354 /** @hide */
355 public int getPriority() {
356 return priority;
357 }
358
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600359 /** @hide */
360 public int getFlags() {
361 return flags;
362 }
363
Makoto Onuki959acb52018-01-26 14:10:03 -0800364 /** @hide */
365 public boolean isExemptedFromAppStandby() {
Makoto Onuki2b5811a2018-02-08 11:09:42 -0800366 return ((flags & FLAG_EXEMPT_FROM_APP_STANDBY) != 0) && !isPeriodic();
Makoto Onuki959acb52018-01-26 14:10:03 -0800367 }
368
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700369 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600370 * @see JobInfo.Builder#setRequiresCharging(boolean)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700371 */
372 public boolean isRequireCharging() {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800373 return (constraintFlags & CONSTRAINT_FLAG_CHARGING) != 0;
374 }
375
376 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600377 * @see JobInfo.Builder#setRequiresBatteryNotLow(boolean)
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800378 */
379 public boolean isRequireBatteryNotLow() {
380 return (constraintFlags & CONSTRAINT_FLAG_BATTERY_NOT_LOW) != 0;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700381 }
382
383 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600384 * @see JobInfo.Builder#setRequiresDeviceIdle(boolean)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700385 */
386 public boolean isRequireDeviceIdle() {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800387 return (constraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0;
388 }
389
390 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600391 * @see JobInfo.Builder#setRequiresStorageNotLow(boolean)
Dianne Hackborn532ea262017-03-17 17:50:55 -0700392 */
393 public boolean isRequireStorageNotLow() {
394 return (constraintFlags & CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0;
395 }
396
397 /**
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800398 * @hide
399 */
400 public int getConstraintFlags() {
401 return constraintFlags;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700402 }
403
404 /**
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800405 * Which content: URIs must change for the job to be scheduled. Returns null
406 * if there are none required.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600407 * @see JobInfo.Builder#addTriggerContentUri(TriggerContentUri)
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800408 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700409 public @Nullable TriggerContentUri[] getTriggerContentUris() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800410 return triggerContentUris;
411 }
412
413 /**
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700414 * When triggering on content URI changes, this is the delay from when a change
415 * is detected until the job is scheduled.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600416 * @see JobInfo.Builder#setTriggerContentUpdateDelay(long)
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700417 */
418 public long getTriggerContentUpdateDelay() {
419 return triggerContentUpdateDelay;
420 }
421
422 /**
423 * When triggering on content URI changes, this is the maximum delay we will
424 * use before scheduling the job.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600425 * @see JobInfo.Builder#setTriggerContentMaxDelay(long)
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700426 */
427 public long getTriggerContentMaxDelay() {
428 return triggerContentMaxDelay;
429 }
430
431 /**
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700432 * Return the basic description of the kind of network this job requires.
433 *
434 * @deprecated This method attempts to map {@link #getRequiredNetwork()}
435 * into the set of simple constants, which results in a loss of
436 * fidelity. Callers should move to using
437 * {@link #getRequiredNetwork()} directly.
438 * @see Builder#setRequiredNetworkType(int)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700439 */
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700440 @Deprecated
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600441 public @NetworkType int getNetworkType() {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700442 if (networkRequest == null) {
443 return NETWORK_TYPE_NONE;
444 } else if (networkRequest.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
445 return NETWORK_TYPE_UNMETERED;
446 } else if (networkRequest.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING)) {
447 return NETWORK_TYPE_NOT_ROAMING;
448 } else if (networkRequest.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
449 return NETWORK_TYPE_CELLULAR;
450 } else {
451 return NETWORK_TYPE_ANY;
452 }
453 }
454
455 /**
456 * Return the detailed description of the kind of network this job requires,
457 * or {@code null} if no specific kind of network is required.
458 *
459 * @see Builder#setRequiredNetwork(NetworkRequest)
460 */
461 public @Nullable NetworkRequest getRequiredNetwork() {
462 return networkRequest;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700463 }
464
465 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600466 * @deprecated replaced by {@link #getEstimatedNetworkDownloadBytes()} and
467 * {@link #getEstimatedNetworkUploadBytes()}.
468 * @removed
469 */
470 @Deprecated
471 public @BytesLong long getEstimatedNetworkBytes() {
472 if (networkDownloadBytes == NETWORK_BYTES_UNKNOWN
473 && networkUploadBytes == NETWORK_BYTES_UNKNOWN) {
474 return NETWORK_BYTES_UNKNOWN;
475 } else if (networkDownloadBytes == NETWORK_BYTES_UNKNOWN) {
476 return networkUploadBytes;
477 } else if (networkUploadBytes == NETWORK_BYTES_UNKNOWN) {
478 return networkDownloadBytes;
479 } else {
480 return networkDownloadBytes + networkUploadBytes;
481 }
482 }
483
484 /**
485 * Return the estimated size of download traffic that will be performed by
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600486 * this job, in bytes.
487 *
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600488 * @return Estimated size of download traffic, or
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600489 * {@link #NETWORK_BYTES_UNKNOWN} when unknown.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600490 * @see Builder#setEstimatedNetworkBytes(long, long)
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600491 */
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600492 public @BytesLong long getEstimatedNetworkDownloadBytes() {
493 return networkDownloadBytes;
494 }
495
496 /**
497 * Return the estimated size of upload traffic that will be performed by
498 * this job, in bytes.
499 *
500 * @return Estimated size of upload traffic, or
501 * {@link #NETWORK_BYTES_UNKNOWN} when unknown.
502 * @see Builder#setEstimatedNetworkBytes(long, long)
503 */
504 public @BytesLong long getEstimatedNetworkUploadBytes() {
505 return networkUploadBytes;
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600506 }
507
508 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700509 * Set for a job that does not recur periodically, to specify a delay after which the job
510 * will be eligible for execution. This value is not set if the job recurs periodically.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600511 * @see JobInfo.Builder#setMinimumLatency(long)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700512 */
513 public long getMinLatencyMillis() {
514 return minLatencyMillis;
515 }
516
517 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600518 * @see JobInfo.Builder#setOverrideDeadline(long)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700519 */
520 public long getMaxExecutionDelayMillis() {
521 return maxExecutionDelayMillis;
522 }
523
524 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700525 * Track whether this job will repeat with a given period.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600526 * @see JobInfo.Builder#setPeriodic(long)
527 * @see JobInfo.Builder#setPeriodic(long, long)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700528 */
529 public boolean isPeriodic() {
530 return isPeriodic;
531 }
532
533 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600534 * @see JobInfo.Builder#setPersisted(boolean)
Matthew Williams900c67f2014-07-09 12:46:53 -0700535 */
536 public boolean isPersisted() {
537 return isPersisted;
538 }
539
540 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700541 * Set to the interval between occurrences of this job. This value is <b>not</b> set if the
542 * job does not recur periodically.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600543 * @see JobInfo.Builder#setPeriodic(long)
544 * @see JobInfo.Builder#setPeriodic(long, long)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700545 */
546 public long getIntervalMillis() {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700547 return intervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000548 }
549
550 /**
Shreyas Basarge9e6d5882016-04-12 10:59:07 +0100551 * Flex time for this job. Only valid if this is a periodic job. The job can
552 * execute at any time in a window of flex length at the end of the period.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600553 * @see JobInfo.Builder#setPeriodic(long)
554 * @see JobInfo.Builder#setPeriodic(long, long)
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000555 */
556 public long getFlexMillis() {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700557 return flexMillis;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700558 }
559
560 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700561 * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
562 * will be increased depending on the backoff policy specified at job creation time. Defaults
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700563 * to 30 seconds, minimum is currently 10 seconds.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600564 * @see JobInfo.Builder#setBackoffCriteria(long, int)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700565 */
566 public long getInitialBackoffMillis() {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700567 return initialBackoffMillis;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700568 }
569
570 /**
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600571 * Return the backoff policy of this job.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600572 * @see JobInfo.Builder#setBackoffCriteria(long, int)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700573 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600574 public @BackoffPolicy int getBackoffPolicy() {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700575 return backoffPolicy;
576 }
577
Matthew Williams9b9244b62014-05-14 11:06:04 -0700578 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600579 * @see JobInfo.Builder#setImportantWhileForeground(boolean)
580 */
581 public boolean isImportantWhileForeground() {
582 return (flags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0;
583 }
584
585 /**
586 * @see JobInfo.Builder#setPrefetch(boolean)
587 */
588 public boolean isPrefetch() {
589 return (flags & FLAG_PREFETCH) != 0;
590 }
591
592 /**
Matthew Williams9b9244b62014-05-14 11:06:04 -0700593 * User can specify an early constraint of 0L, which is valid, so we keep track of whether the
594 * function was called at all.
595 * @hide
596 */
597 public boolean hasEarlyConstraint() {
598 return hasEarlyConstraint;
599 }
600
601 /**
602 * User can specify a late constraint of 0L, which is valid, so we keep track of whether the
603 * function was called at all.
604 * @hide
605 */
606 public boolean hasLateConstraint() {
607 return hasLateConstraint;
608 }
609
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700610 private static boolean kindofEqualsBundle(BaseBundle a, BaseBundle b) {
611 return (a == b) || (a != null && a.kindofEquals(b));
612 }
613
614 @Override
615 public boolean equals(Object o) {
616 if (!(o instanceof JobInfo)) {
617 return false;
618 }
619 JobInfo j = (JobInfo) o;
620 if (jobId != j.jobId) {
621 return false;
622 }
623 // XXX won't be correct if one is parcelled and the other not.
624 if (!kindofEqualsBundle(extras, j.extras)) {
625 return false;
626 }
627 // XXX won't be correct if one is parcelled and the other not.
628 if (!kindofEqualsBundle(transientExtras, j.transientExtras)) {
629 return false;
630 }
631 // XXX for now we consider two different clip data objects to be different,
632 // regardless of whether their contents are the same.
633 if (clipData != j.clipData) {
634 return false;
635 }
636 if (clipGrantFlags != j.clipGrantFlags) {
637 return false;
638 }
639 if (!Objects.equals(service, j.service)) {
640 return false;
641 }
642 if (constraintFlags != j.constraintFlags) {
643 return false;
644 }
Paul Duffinc67663c2017-05-26 09:46:48 +0100645 if (!Arrays.equals(triggerContentUris, j.triggerContentUris)) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700646 return false;
647 }
648 if (triggerContentUpdateDelay != j.triggerContentUpdateDelay) {
649 return false;
650 }
651 if (triggerContentMaxDelay != j.triggerContentMaxDelay) {
652 return false;
653 }
654 if (hasEarlyConstraint != j.hasEarlyConstraint) {
655 return false;
656 }
657 if (hasLateConstraint != j.hasLateConstraint) {
658 return false;
659 }
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700660 if (!Objects.equals(networkRequest, j.networkRequest)) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700661 return false;
662 }
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600663 if (networkDownloadBytes != j.networkDownloadBytes) {
664 return false;
665 }
666 if (networkUploadBytes != j.networkUploadBytes) {
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600667 return false;
668 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700669 if (minLatencyMillis != j.minLatencyMillis) {
670 return false;
671 }
672 if (maxExecutionDelayMillis != j.maxExecutionDelayMillis) {
673 return false;
674 }
675 if (isPeriodic != j.isPeriodic) {
676 return false;
677 }
678 if (isPersisted != j.isPersisted) {
679 return false;
680 }
681 if (intervalMillis != j.intervalMillis) {
682 return false;
683 }
684 if (flexMillis != j.flexMillis) {
685 return false;
686 }
687 if (initialBackoffMillis != j.initialBackoffMillis) {
688 return false;
689 }
690 if (backoffPolicy != j.backoffPolicy) {
691 return false;
692 }
693 if (priority != j.priority) {
694 return false;
695 }
696 if (flags != j.flags) {
697 return false;
698 }
699 return true;
700 }
701
702 @Override
703 public int hashCode() {
704 int hashCode = jobId;
705 if (extras != null) {
Paul Duffinc67663c2017-05-26 09:46:48 +0100706 hashCode = 31 * hashCode + extras.hashCode();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700707 }
708 if (transientExtras != null) {
Paul Duffinc67663c2017-05-26 09:46:48 +0100709 hashCode = 31 * hashCode + transientExtras.hashCode();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700710 }
711 if (clipData != null) {
Paul Duffinc67663c2017-05-26 09:46:48 +0100712 hashCode = 31 * hashCode + clipData.hashCode();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700713 }
714 hashCode = 31*hashCode + clipGrantFlags;
715 if (service != null) {
Paul Duffinc67663c2017-05-26 09:46:48 +0100716 hashCode = 31 * hashCode + service.hashCode();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700717 }
Paul Duffinc67663c2017-05-26 09:46:48 +0100718 hashCode = 31 * hashCode + constraintFlags;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700719 if (triggerContentUris != null) {
Paul Duffinc67663c2017-05-26 09:46:48 +0100720 hashCode = 31 * hashCode + Arrays.hashCode(triggerContentUris);
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700721 }
Paul Duffinc67663c2017-05-26 09:46:48 +0100722 hashCode = 31 * hashCode + Long.hashCode(triggerContentUpdateDelay);
723 hashCode = 31 * hashCode + Long.hashCode(triggerContentMaxDelay);
724 hashCode = 31 * hashCode + Boolean.hashCode(hasEarlyConstraint);
725 hashCode = 31 * hashCode + Boolean.hashCode(hasLateConstraint);
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700726 if (networkRequest != null) {
727 hashCode = 31 * hashCode + networkRequest.hashCode();
728 }
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600729 hashCode = 31 * hashCode + Long.hashCode(networkDownloadBytes);
730 hashCode = 31 * hashCode + Long.hashCode(networkUploadBytes);
Paul Duffinc67663c2017-05-26 09:46:48 +0100731 hashCode = 31 * hashCode + Long.hashCode(minLatencyMillis);
732 hashCode = 31 * hashCode + Long.hashCode(maxExecutionDelayMillis);
733 hashCode = 31 * hashCode + Boolean.hashCode(isPeriodic);
734 hashCode = 31 * hashCode + Boolean.hashCode(isPersisted);
735 hashCode = 31 * hashCode + Long.hashCode(intervalMillis);
736 hashCode = 31 * hashCode + Long.hashCode(flexMillis);
737 hashCode = 31 * hashCode + Long.hashCode(initialBackoffMillis);
738 hashCode = 31 * hashCode + backoffPolicy;
739 hashCode = 31 * hashCode + priority;
740 hashCode = 31 * hashCode + flags;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700741 return hashCode;
742 }
743
Christopher Tate7060b042014-06-09 19:50:00 -0700744 private JobInfo(Parcel in) {
745 jobId = in.readInt();
Matthew Williams3d86fd22014-05-16 18:02:17 -0700746 extras = in.readPersistableBundle();
Dianne Hackbornba604732016-02-10 17:05:10 -0800747 transientExtras = in.readBundle();
Dianne Hackborna47223f2017-03-30 13:49:13 -0700748 if (in.readInt() != 0) {
749 clipData = ClipData.CREATOR.createFromParcel(in);
750 clipGrantFlags = in.readInt();
751 } else {
752 clipData = null;
753 clipGrantFlags = 0;
754 }
Matthew Williamseffacfa2014-06-05 20:56:40 -0700755 service = in.readParcelable(null);
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800756 constraintFlags = in.readInt();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800757 triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR);
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700758 triggerContentUpdateDelay = in.readLong();
759 triggerContentMaxDelay = in.readLong();
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700760 if (in.readInt() != 0) {
761 networkRequest = NetworkRequest.CREATOR.createFromParcel(in);
762 } else {
763 networkRequest = null;
764 }
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600765 networkDownloadBytes = in.readLong();
766 networkUploadBytes = in.readLong();
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700767 minLatencyMillis = in.readLong();
768 maxExecutionDelayMillis = in.readLong();
769 isPeriodic = in.readInt() == 1;
Matthew Williams900c67f2014-07-09 12:46:53 -0700770 isPersisted = in.readInt() == 1;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700771 intervalMillis = in.readLong();
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000772 flexMillis = in.readLong();
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700773 initialBackoffMillis = in.readLong();
774 backoffPolicy = in.readInt();
Matthew Williams9b9244b62014-05-14 11:06:04 -0700775 hasEarlyConstraint = in.readInt() == 1;
776 hasLateConstraint = in.readInt() == 1;
Shreyas Basarge5db09082016-01-07 13:38:29 +0000777 priority = in.readInt();
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600778 flags = in.readInt();
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700779 }
780
Christopher Tate7060b042014-06-09 19:50:00 -0700781 private JobInfo(JobInfo.Builder b) {
782 jobId = b.mJobId;
Dianne Hackborn2510b372017-03-03 17:01:38 -0800783 extras = b.mExtras.deepCopy();
784 transientExtras = b.mTransientExtras.deepCopy();
Dianne Hackborna47223f2017-03-30 13:49:13 -0700785 clipData = b.mClipData;
786 clipGrantFlags = b.mClipGrantFlags;
Christopher Tate7060b042014-06-09 19:50:00 -0700787 service = b.mJobService;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800788 constraintFlags = b.mConstraintFlags;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800789 triggerContentUris = b.mTriggerContentUris != null
790 ? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()])
791 : null;
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700792 triggerContentUpdateDelay = b.mTriggerContentUpdateDelay;
793 triggerContentMaxDelay = b.mTriggerContentMaxDelay;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700794 networkRequest = b.mNetworkRequest;
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600795 networkDownloadBytes = b.mNetworkDownloadBytes;
796 networkUploadBytes = b.mNetworkUploadBytes;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700797 minLatencyMillis = b.mMinLatencyMillis;
798 maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
799 isPeriodic = b.mIsPeriodic;
Matthew Williams900c67f2014-07-09 12:46:53 -0700800 isPersisted = b.mIsPersisted;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700801 intervalMillis = b.mIntervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000802 flexMillis = b.mFlexMillis;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700803 initialBackoffMillis = b.mInitialBackoffMillis;
804 backoffPolicy = b.mBackoffPolicy;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700805 hasEarlyConstraint = b.mHasEarlyConstraint;
806 hasLateConstraint = b.mHasLateConstraint;
Shreyas Basarge5db09082016-01-07 13:38:29 +0000807 priority = b.mPriority;
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600808 flags = b.mFlags;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700809 }
810
811 @Override
812 public int describeContents() {
813 return 0;
814 }
815
816 @Override
817 public void writeToParcel(Parcel out, int flags) {
Christopher Tate7060b042014-06-09 19:50:00 -0700818 out.writeInt(jobId);
Matthew Williams3d86fd22014-05-16 18:02:17 -0700819 out.writePersistableBundle(extras);
Dianne Hackbornba604732016-02-10 17:05:10 -0800820 out.writeBundle(transientExtras);
Dianne Hackborna47223f2017-03-30 13:49:13 -0700821 if (clipData != null) {
822 out.writeInt(1);
823 clipData.writeToParcel(out, flags);
824 out.writeInt(clipGrantFlags);
825 } else {
826 out.writeInt(0);
827 }
Matthew Williamseffacfa2014-06-05 20:56:40 -0700828 out.writeParcelable(service, flags);
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800829 out.writeInt(constraintFlags);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800830 out.writeTypedArray(triggerContentUris, flags);
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700831 out.writeLong(triggerContentUpdateDelay);
832 out.writeLong(triggerContentMaxDelay);
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700833 if (networkRequest != null) {
834 out.writeInt(1);
835 networkRequest.writeToParcel(out, flags);
836 } else {
837 out.writeInt(0);
838 }
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600839 out.writeLong(networkDownloadBytes);
840 out.writeLong(networkUploadBytes);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700841 out.writeLong(minLatencyMillis);
842 out.writeLong(maxExecutionDelayMillis);
843 out.writeInt(isPeriodic ? 1 : 0);
Matthew Williams900c67f2014-07-09 12:46:53 -0700844 out.writeInt(isPersisted ? 1 : 0);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700845 out.writeLong(intervalMillis);
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000846 out.writeLong(flexMillis);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700847 out.writeLong(initialBackoffMillis);
848 out.writeInt(backoffPolicy);
Matthew Williams9b9244b62014-05-14 11:06:04 -0700849 out.writeInt(hasEarlyConstraint ? 1 : 0);
850 out.writeInt(hasLateConstraint ? 1 : 0);
Shreyas Basarge5db09082016-01-07 13:38:29 +0000851 out.writeInt(priority);
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600852 out.writeInt(this.flags);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700853 }
854
Christopher Tate7060b042014-06-09 19:50:00 -0700855 public static final Creator<JobInfo> CREATOR = new Creator<JobInfo>() {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700856 @Override
Christopher Tate7060b042014-06-09 19:50:00 -0700857 public JobInfo createFromParcel(Parcel in) {
858 return new JobInfo(in);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700859 }
860
861 @Override
Christopher Tate7060b042014-06-09 19:50:00 -0700862 public JobInfo[] newArray(int size) {
863 return new JobInfo[size];
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700864 }
865 };
866
Matthew Williamsee410da2014-07-25 11:30:40 -0700867 @Override
868 public String toString() {
869 return "(job:" + jobId + "/" + service.flattenToShortString() + ")";
870 }
871
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800872 /**
873 * Information about a content URI modification that a job would like to
874 * trigger on.
875 */
876 public static final class TriggerContentUri implements Parcelable {
877 private final Uri mUri;
878 private final int mFlags;
879
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600880 /** @hide */
881 @Retention(RetentionPolicy.SOURCE)
882 @IntDef(flag = true, prefix = { "FLAG_" }, value = {
883 FLAG_NOTIFY_FOR_DESCENDANTS,
884 })
885 public @interface Flags { }
886
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800887 /**
888 * Flag for trigger: also trigger if any descendants of the given URI change.
889 * Corresponds to the <var>notifyForDescendants</var> of
890 * {@link android.content.ContentResolver#registerContentObserver}.
891 */
892 public static final int FLAG_NOTIFY_FOR_DESCENDANTS = 1<<0;
893
894 /**
895 * Create a new trigger description.
896 * @param uri The URI to observe. Must be non-null.
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600897 * @param flags Flags for the observer.
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800898 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600899 public TriggerContentUri(@NonNull Uri uri, @Flags int flags) {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800900 mUri = uri;
901 mFlags = flags;
902 }
903
904 /**
905 * Return the Uri this trigger was created for.
906 */
907 public Uri getUri() {
908 return mUri;
909 }
910
911 /**
912 * Return the flags supplied for the trigger.
913 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600914 public @Flags int getFlags() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800915 return mFlags;
916 }
917
Dianne Hackborn121e1642016-06-21 20:39:02 -0700918 @Override
919 public boolean equals(Object o) {
920 if (!(o instanceof TriggerContentUri)) {
921 return false;
922 }
923 TriggerContentUri t = (TriggerContentUri) o;
924 return Objects.equals(t.mUri, mUri) && t.mFlags == mFlags;
925 }
926
927 @Override
928 public int hashCode() {
929 return (mUri == null ? 0 : mUri.hashCode()) ^ mFlags;
930 }
931
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800932 private TriggerContentUri(Parcel in) {
933 mUri = Uri.CREATOR.createFromParcel(in);
934 mFlags = in.readInt();
935 }
936
937 @Override
938 public int describeContents() {
939 return 0;
940 }
941
942 @Override
943 public void writeToParcel(Parcel out, int flags) {
944 mUri.writeToParcel(out, flags);
945 out.writeInt(mFlags);
946 }
947
948 public static final Creator<TriggerContentUri> CREATOR = new Creator<TriggerContentUri>() {
949 @Override
950 public TriggerContentUri createFromParcel(Parcel in) {
951 return new TriggerContentUri(in);
952 }
953
954 @Override
955 public TriggerContentUri[] newArray(int size) {
956 return new TriggerContentUri[size];
957 }
958 };
959 }
960
Christopher Tate7060b042014-06-09 19:50:00 -0700961 /** Builder class for constructing {@link JobInfo} objects. */
Matthew Williams9b9244b62014-05-14 11:06:04 -0700962 public static final class Builder {
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700963 private final int mJobId;
964 private final ComponentName mJobService;
Matthew Williams3d86fd22014-05-16 18:02:17 -0700965 private PersistableBundle mExtras = PersistableBundle.EMPTY;
Dianne Hackbornba604732016-02-10 17:05:10 -0800966 private Bundle mTransientExtras = Bundle.EMPTY;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700967 private ClipData mClipData;
968 private int mClipGrantFlags;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800969 private int mPriority = PRIORITY_DEFAULT;
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600970 private int mFlags;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700971 // Requirements.
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800972 private int mConstraintFlags;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700973 private NetworkRequest mNetworkRequest;
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600974 private long mNetworkDownloadBytes = NETWORK_BYTES_UNKNOWN;
975 private long mNetworkUploadBytes = NETWORK_BYTES_UNKNOWN;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800976 private ArrayList<TriggerContentUri> mTriggerContentUris;
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700977 private long mTriggerContentUpdateDelay = -1;
978 private long mTriggerContentMaxDelay = -1;
Matthew Williams900c67f2014-07-09 12:46:53 -0700979 private boolean mIsPersisted;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700980 // One-off parameters.
981 private long mMinLatencyMillis;
982 private long mMaxExecutionDelayMillis;
983 // Periodic parameters.
984 private boolean mIsPeriodic;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700985 private boolean mHasEarlyConstraint;
986 private boolean mHasLateConstraint;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700987 private long mIntervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000988 private long mFlexMillis;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700989 // Back-off parameters.
Matthew Williams3d86fd22014-05-16 18:02:17 -0700990 private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS;
991 private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700992 /** Easy way to track whether the client has tried to set a back-off policy. */
993 private boolean mBackoffPolicySet = false;
994
995 /**
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700996 * Initialize a new Builder to construct a {@link JobInfo}.
997 *
Christopher Tate7060b042014-06-09 19:50:00 -0700998 * @param jobId Application-provided id for this job. Subsequent calls to cancel, or
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700999 * jobs created with the same jobId, will update the pre-existing job with
1000 * the same id. This ID must be unique across all clients of the same uid
1001 * (not just the same package). You will want to make sure this is a stable
1002 * id across app updates, so probably not based on a resource ID.
Christopher Tate7060b042014-06-09 19:50:00 -07001003 * @param jobService The endpoint that you implement that will receive the callback from the
Dianne Hackborne9a988c2016-05-27 17:59:40 -07001004 * JobScheduler.
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001005 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001006 public Builder(int jobId, @NonNull ComponentName jobService) {
Christopher Tate7060b042014-06-09 19:50:00 -07001007 mJobService = jobService;
1008 mJobId = jobId;
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001009 }
1010
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001011 /** @hide */
Shreyas Basarge5db09082016-01-07 13:38:29 +00001012 public Builder setPriority(int priority) {
1013 mPriority = priority;
1014 return this;
1015 }
1016
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001017 /** @hide */
1018 public Builder setFlags(int flags) {
1019 mFlags = flags;
1020 return this;
1021 }
1022
Shreyas Basarge5db09082016-01-07 13:38:29 +00001023 /**
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001024 * Set optional extras. This is persisted, so we only allow primitive types.
1025 * @param extras Bundle containing extras you want the scheduler to hold on to for you.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001026 * @see JobInfo#getExtras()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001027 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001028 public Builder setExtras(@NonNull PersistableBundle extras) {
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001029 mExtras = extras;
1030 return this;
1031 }
1032
1033 /**
Dianne Hackborn28d1b662017-04-21 14:17:23 -07001034 * Set optional transient extras.
1035 *
1036 * <p>Because setting this property is not compatible with persisted
1037 * jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
1038 * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
1039 *
Dianne Hackbornba604732016-02-10 17:05:10 -08001040 * @param extras Bundle containing extras you want the scheduler to hold on to for you.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001041 * @see JobInfo#getTransientExtras()
Dianne Hackbornba604732016-02-10 17:05:10 -08001042 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001043 public Builder setTransientExtras(@NonNull Bundle extras) {
Dianne Hackbornba604732016-02-10 17:05:10 -08001044 mTransientExtras = extras;
1045 return this;
1046 }
1047
1048 /**
Dianne Hackborna47223f2017-03-30 13:49:13 -07001049 * Set a {@link ClipData} associated with this Job.
1050 *
1051 * <p>The main purpose of providing a ClipData is to allow granting of
1052 * URI permissions for data associated with the clip. The exact kind
1053 * of permission grant to perform is specified through <var>grantFlags</var>.
1054 *
1055 * <p>If the ClipData contains items that are Intents, any
1056 * grant flags in those Intents will be ignored. Only flags provided as an argument
1057 * to this method are respected, and will be applied to all Uri or
1058 * Intent items in the clip (or sub-items of the clip).
1059 *
1060 * <p>Because setting this property is not compatible with persisted
1061 * jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
1062 * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
1063 *
1064 * @param clip The new clip to set. May be null to clear the current clip.
1065 * @param grantFlags The desired permissions to grant for any URIs. This should be
1066 * a combination of {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION},
1067 * {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, and
1068 * {@link android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION}.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001069 * @see JobInfo#getClipData()
1070 * @see JobInfo#getClipGrantFlags()
Dianne Hackborna47223f2017-03-30 13:49:13 -07001071 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001072 public Builder setClipData(@Nullable ClipData clip, int grantFlags) {
Dianne Hackborna47223f2017-03-30 13:49:13 -07001073 mClipData = clip;
1074 mClipGrantFlags = grantFlags;
1075 return this;
1076 }
1077
1078 /**
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001079 * Set basic description of the kind of network your job requires. If
1080 * you need more precise control over network capabilities, see
1081 * {@link #setRequiredNetwork(NetworkRequest)}.
1082 * <p>
1083 * If your job doesn't need a network connection, you don't need to call
1084 * this method, as the default value is {@link #NETWORK_TYPE_NONE}.
1085 * <p>
1086 * Calling this method defines network as a strict requirement for your
1087 * job. If the network requested is not available your job will never
1088 * run. See {@link #setOverrideDeadline(long)} to change this behavior.
1089 * Calling this method will override any requirements previously defined
1090 * by {@link #setRequiredNetwork(NetworkRequest)}; you typically only
1091 * want to call one of these methods.
Jeff Sharkey76a02412017-10-24 16:55:04 -06001092 * <p class="note">
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001093 * When your job executes in
Jeff Sharkey76a02412017-10-24 16:55:04 -06001094 * {@link JobService#onStartJob(JobParameters)}, be sure to use the
1095 * specific network returned by {@link JobParameters#getNetwork()},
1096 * otherwise you'll use the default network which may not meet this
1097 * constraint.
1098 *
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001099 * @see #setRequiredNetwork(NetworkRequest)
1100 * @see JobInfo#getNetworkType()
Jeff Sharkey76a02412017-10-24 16:55:04 -06001101 * @see JobParameters#getNetwork()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001102 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -06001103 public Builder setRequiredNetworkType(@NetworkType int networkType) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001104 if (networkType == NETWORK_TYPE_NONE) {
1105 return setRequiredNetwork(null);
1106 } else {
1107 final NetworkRequest.Builder builder = new NetworkRequest.Builder();
1108
1109 // All types require validated Internet
1110 builder.addCapability(NET_CAPABILITY_INTERNET);
1111 builder.addCapability(NET_CAPABILITY_VALIDATED);
1112 builder.removeCapability(NET_CAPABILITY_NOT_VPN);
1113
1114 if (networkType == NETWORK_TYPE_ANY) {
1115 // No other capabilities
1116 } else if (networkType == NETWORK_TYPE_UNMETERED) {
1117 builder.addCapability(NET_CAPABILITY_NOT_METERED);
1118 } else if (networkType == NETWORK_TYPE_NOT_ROAMING) {
1119 builder.addCapability(NET_CAPABILITY_NOT_ROAMING);
1120 } else if (networkType == NETWORK_TYPE_CELLULAR) {
1121 builder.addTransportType(TRANSPORT_CELLULAR);
1122 }
1123
1124 return setRequiredNetwork(builder.build());
1125 }
1126 }
1127
1128 /**
1129 * Set detailed description of the kind of network your job requires.
1130 * <p>
1131 * If your job doesn't need a network connection, you don't need to call
1132 * this method, as the default is {@code null}.
1133 * <p>
1134 * Calling this method defines network as a strict requirement for your
1135 * job. If the network requested is not available your job will never
1136 * run. See {@link #setOverrideDeadline(long)} to change this behavior.
1137 * Calling this method will override any requirements previously defined
1138 * by {@link #setRequiredNetworkType(int)}; you typically only want to
1139 * call one of these methods.
1140 * <p class="note">
1141 * When your job executes in
1142 * {@link JobService#onStartJob(JobParameters)}, be sure to use the
1143 * specific network returned by {@link JobParameters#getNetwork()},
1144 * otherwise you'll use the default network which may not meet this
1145 * constraint.
1146 *
1147 * @param networkRequest The detailed description of the kind of network
1148 * this job requires, or {@code null} if no specific kind of
1149 * network is required. Defining a {@link NetworkSpecifier}
1150 * is only supported for jobs that aren't persisted.
1151 * @see #setRequiredNetworkType(int)
1152 * @see JobInfo#getRequiredNetwork()
1153 * @see JobParameters#getNetwork()
1154 */
1155 public Builder setRequiredNetwork(@Nullable NetworkRequest networkRequest) {
1156 mNetworkRequest = networkRequest;
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001157 return this;
1158 }
1159
Christopher Tate7060b042014-06-09 19:50:00 -07001160 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001161 * @deprecated replaced by
1162 * {@link #setEstimatedNetworkBytes(long, long)}.
1163 * @removed
1164 */
1165 @Deprecated
1166 public Builder setEstimatedNetworkBytes(@BytesLong long networkBytes) {
1167 return setEstimatedNetworkBytes(networkBytes, NETWORK_BYTES_UNKNOWN);
1168 }
1169
1170 /**
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001171 * Set the estimated size of network traffic that will be performed by
1172 * this job, in bytes.
1173 * <p>
1174 * Apps are encouraged to provide values that are as accurate as
1175 * possible, but when the exact size isn't available, an
1176 * order-of-magnitude estimate can be provided instead. Here are some
1177 * specific examples:
1178 * <ul>
1179 * <li>A job that is backing up a photo knows the exact size of that
1180 * photo, so it should provide that size as the estimate.
1181 * <li>A job that refreshes top news stories wouldn't know an exact
1182 * size, but if the size is expected to be consistently around 100KB, it
1183 * can provide that order-of-magnitude value as the estimate.
1184 * <li>A job that synchronizes email could end up using an extreme range
1185 * of data, from under 1KB when nothing has changed, to dozens of MB
1186 * when there are new emails with attachments. Jobs that cannot provide
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001187 * reasonable estimates should use the sentinel value
1188 * {@link JobInfo#NETWORK_BYTES_UNKNOWN}.
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001189 * </ul>
1190 * Note that the system may choose to delay jobs with large network
1191 * usage estimates when the device has a poor network connection, in
1192 * order to save battery.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001193 * <p>
1194 * The values provided here only reflect the traffic that will be
1195 * performed by the base job; if you're using {@link JobWorkItem} then
1196 * you also need to define the network traffic used by each work item
1197 * when constructing them.
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001198 *
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001199 * @param downloadBytes The estimated size of network traffic that will
1200 * be downloaded by this job, in bytes.
1201 * @param uploadBytes The estimated size of network traffic that will be
1202 * uploaded by this job, in bytes.
1203 * @see JobInfo#getEstimatedNetworkDownloadBytes()
1204 * @see JobInfo#getEstimatedNetworkUploadBytes()
1205 * @see JobWorkItem#JobWorkItem(android.content.Intent, long, long)
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001206 */
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001207 public Builder setEstimatedNetworkBytes(@BytesLong long downloadBytes,
1208 @BytesLong long uploadBytes) {
1209 mNetworkDownloadBytes = downloadBytes;
1210 mNetworkUploadBytes = uploadBytes;
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001211 return this;
1212 }
1213
1214 /**
Christopher Tate78152512017-10-02 17:07:07 -07001215 * Specify that to run this job, the device must be charging (or be a
1216 * non-battery-powered device connected to permanent power, such as Android TV
1217 * devices). This defaults to {@code false}.
1218 *
1219 * <p class="note">For purposes of running jobs, a battery-powered device
1220 * "charging" is not quite the same as simply being connected to power. If the
1221 * device is so busy that the battery is draining despite a power connection, jobs
1222 * with this constraint will <em>not</em> run. This can happen during some
1223 * common use cases such as video chat, particularly if the device is plugged in
1224 * to USB rather than to wall power.
1225 *
1226 * @param requiresCharging Pass {@code true} to require that the device be
1227 * charging in order to run the job.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001228 * @see JobInfo#isRequireCharging()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001229 */
1230 public Builder setRequiresCharging(boolean requiresCharging) {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001231 mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_CHARGING)
1232 | (requiresCharging ? CONSTRAINT_FLAG_CHARGING : 0);
1233 return this;
1234 }
1235
1236 /**
1237 * Specify that to run this job, the device's battery level must not be low.
1238 * This defaults to false. If true, the job will only run when the battery level
1239 * is not low, which is generally the point where the user is given a "low battery"
1240 * warning.
1241 * @param batteryNotLow Whether or not the device's battery level must not be low.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001242 * @see JobInfo#isRequireBatteryNotLow()
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001243 */
1244 public Builder setRequiresBatteryNotLow(boolean batteryNotLow) {
1245 mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_BATTERY_NOT_LOW)
1246 | (batteryNotLow ? CONSTRAINT_FLAG_BATTERY_NOT_LOW : 0);
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001247 return this;
1248 }
1249
1250 /**
Christopher Tate78152512017-10-02 17:07:07 -07001251 * When set {@code true}, ensure that this job will not run if the device is in active use.
1252 * The default state is {@code false}: that is, the for the job to be runnable even when
1253 * someone is interacting with the device.
1254 *
1255 * <p>This state is a loose definition provided by the system. In general, it means that
1256 * the device is not currently being used interactively, and has not been in use for some
1257 * time. As such, it is a good time to perform resource heavy jobs. Bear in mind that
1258 * battery usage will still be attributed to your application, and surfaced to the user in
1259 * battery stats.</p>
1260 *
1261 * <p class="note">Despite the similar naming, this job constraint is <em>not</em>
1262 * related to the system's "device idle" or "doze" states. This constraint only
1263 * determines whether a job is allowed to run while the device is directly in use.
1264 *
1265 * @param requiresDeviceIdle Pass {@code true} to prevent the job from running
1266 * while the device is being used interactively.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001267 * @see JobInfo#isRequireDeviceIdle()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001268 */
1269 public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001270 mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_DEVICE_IDLE)
1271 | (requiresDeviceIdle ? CONSTRAINT_FLAG_DEVICE_IDLE : 0);
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001272 return this;
1273 }
1274
1275 /**
Dianne Hackborn532ea262017-03-17 17:50:55 -07001276 * Specify that to run this job, the device's available storage must not be low.
1277 * This defaults to false. If true, the job will only run when the device is not
1278 * in a low storage state, which is generally the point where the user is given a
1279 * "low storage" warning.
1280 * @param storageNotLow Whether or not the device's available storage must not be low.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001281 * @see JobInfo#isRequireStorageNotLow()
Dianne Hackborn532ea262017-03-17 17:50:55 -07001282 */
1283 public Builder setRequiresStorageNotLow(boolean storageNotLow) {
1284 mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_STORAGE_NOT_LOW)
1285 | (storageNotLow ? CONSTRAINT_FLAG_STORAGE_NOT_LOW : 0);
1286 return this;
1287 }
1288
1289 /**
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001290 * Add a new content: URI that will be monitored with a
1291 * {@link android.database.ContentObserver}, and will cause the job to execute if changed.
1292 * If you have any trigger content URIs associated with a job, it will not execute until
1293 * there has been a change report for one or more of them.
Dianne Hackborn532ea262017-03-17 17:50:55 -07001294 *
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001295 * <p>Note that trigger URIs can not be used in combination with
1296 * {@link #setPeriodic(long)} or {@link #setPersisted(boolean)}. To continually monitor
1297 * for content changes, you need to schedule a new JobInfo observing the same URIs
Dianne Hackborn532ea262017-03-17 17:50:55 -07001298 * before you finish execution of the JobService handling the most recent changes.
1299 * Following this pattern will ensure you do not lost any content changes: while your
1300 * job is running, the system will continue monitoring for content changes, and propagate
1301 * any it sees over to the next job you schedule.</p>
1302 *
1303 * <p>Because setting this property is not compatible with periodic or
Dianne Hackborn46499a52016-03-09 17:57:48 -08001304 * persisted jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
1305 * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
Dianne Hackbornc43a7f82016-06-01 10:48:43 -07001306 *
1307 * <p>The following example shows how this feature can be used to monitor for changes
1308 * in the photos on a device.</p>
1309 *
1310 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/PhotosContentJob.java
1311 * job}
1312 *
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001313 * @param uri The content: URI to monitor.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001314 * @see JobInfo#getTriggerContentUris()
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001315 */
1316 public Builder addTriggerContentUri(@NonNull TriggerContentUri uri) {
1317 if (mTriggerContentUris == null) {
1318 mTriggerContentUris = new ArrayList<>();
1319 }
1320 mTriggerContentUris.add(uri);
1321 return this;
1322 }
1323
1324 /**
Dianne Hackborn8db0fc12016-04-12 13:48:25 -07001325 * Set the delay (in milliseconds) from when a content change is detected until
1326 * the job is scheduled. If there are more changes during that time, the delay
1327 * will be reset to start at the time of the most recent change.
1328 * @param durationMs Delay after most recent content change, in milliseconds.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001329 * @see JobInfo#getTriggerContentUpdateDelay()
Dianne Hackborn8db0fc12016-04-12 13:48:25 -07001330 */
1331 public Builder setTriggerContentUpdateDelay(long durationMs) {
1332 mTriggerContentUpdateDelay = durationMs;
1333 return this;
1334 }
1335
1336 /**
1337 * Set the maximum total delay (in milliseconds) that is allowed from the first
1338 * time a content change is detected until the job is scheduled.
1339 * @param durationMs Delay after initial content change, in milliseconds.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001340 * @see JobInfo#getTriggerContentMaxDelay()
Dianne Hackborn8db0fc12016-04-12 13:48:25 -07001341 */
1342 public Builder setTriggerContentMaxDelay(long durationMs) {
1343 mTriggerContentMaxDelay = durationMs;
1344 return this;
1345 }
1346
1347 /**
Christopher Tate7060b042014-06-09 19:50:00 -07001348 * Specify that this job should recur with the provided interval, not more than once per
1349 * period. You have no control over when within this interval this job will be executed,
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001350 * only the guarantee that it will be executed at most once within this interval.
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001351 * Setting this function on the builder with {@link #setMinimumLatency(long)} or
1352 * {@link #setOverrideDeadline(long)} will result in an error.
Christopher Tate7060b042014-06-09 19:50:00 -07001353 * @param intervalMillis Millisecond interval for which this job will repeat.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001354 * @see JobInfo#getIntervalMillis()
1355 * @see JobInfo#getFlexMillis()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001356 */
1357 public Builder setPeriodic(long intervalMillis) {
Shreyas Basarge89ee6182015-12-17 15:16:36 +00001358 return setPeriodic(intervalMillis, intervalMillis);
1359 }
1360
1361 /**
1362 * Specify that this job should recur with the provided interval and flex. The job can
1363 * execute at any time in a window of flex length at the end of the period.
Shreyas Basargee96c3b72016-01-29 19:25:51 +00001364 * @param intervalMillis Millisecond interval for which this job will repeat. A minimum
Christopher Tatea9b4f3f2016-05-18 13:57:37 -07001365 * value of {@link #getMinPeriodMillis()} is enforced.
Shreyas Basarge89ee6182015-12-17 15:16:36 +00001366 * @param flexMillis Millisecond flex for this job. Flex is clamped to be at least
Christopher Tatea9b4f3f2016-05-18 13:57:37 -07001367 * {@link #getMinFlexMillis()} or 5 percent of the period, whichever is
Shreyas Basarge89ee6182015-12-17 15:16:36 +00001368 * higher.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001369 * @see JobInfo#getIntervalMillis()
1370 * @see JobInfo#getFlexMillis()
Shreyas Basarge89ee6182015-12-17 15:16:36 +00001371 */
1372 public Builder setPeriodic(long intervalMillis, long flexMillis) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001373 final long minPeriod = getMinPeriodMillis();
1374 if (intervalMillis < minPeriod) {
1375 Log.w(TAG, "Requested interval " + formatDuration(intervalMillis) + " for job "
1376 + mJobId + " is too small; raising to " + formatDuration(minPeriod));
1377 intervalMillis = minPeriod;
1378 }
1379
1380 final long percentClamp = 5 * intervalMillis / 100;
1381 final long minFlex = Math.max(percentClamp, getMinFlexMillis());
1382 if (flexMillis < minFlex) {
1383 Log.w(TAG, "Requested flex " + formatDuration(flexMillis) + " for job " + mJobId
1384 + " is too small; raising to " + formatDuration(minFlex));
1385 flexMillis = minFlex;
1386 }
1387
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001388 mIsPeriodic = true;
1389 mIntervalMillis = intervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +00001390 mFlexMillis = flexMillis;
Matthew Williams9b9244b62014-05-14 11:06:04 -07001391 mHasEarlyConstraint = mHasLateConstraint = true;
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001392 return this;
1393 }
1394
1395 /**
Christopher Tate7060b042014-06-09 19:50:00 -07001396 * Specify that this job should be delayed by the provided amount of time.
1397 * Because it doesn't make sense setting this property on a periodic job, doing so will
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001398 * throw an {@link java.lang.IllegalArgumentException} when
Christopher Tate7060b042014-06-09 19:50:00 -07001399 * {@link android.app.job.JobInfo.Builder#build()} is called.
1400 * @param minLatencyMillis Milliseconds before which this job will not be considered for
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001401 * execution.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001402 * @see JobInfo#getMinLatencyMillis()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001403 */
1404 public Builder setMinimumLatency(long minLatencyMillis) {
1405 mMinLatencyMillis = minLatencyMillis;
Matthew Williams9b9244b62014-05-14 11:06:04 -07001406 mHasEarlyConstraint = true;
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001407 return this;
1408 }
1409
1410 /**
Christopher Tate7060b042014-06-09 19:50:00 -07001411 * Set deadline which is the maximum scheduling latency. The job will be run by this
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001412 * deadline even if other requirements are not met. Because it doesn't make sense setting
Christopher Tate7060b042014-06-09 19:50:00 -07001413 * this property on a periodic job, doing so will throw an
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001414 * {@link java.lang.IllegalArgumentException} when
Christopher Tate7060b042014-06-09 19:50:00 -07001415 * {@link android.app.job.JobInfo.Builder#build()} is called.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001416 * @see JobInfo#getMaxExecutionDelayMillis()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001417 */
1418 public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
1419 mMaxExecutionDelayMillis = maxExecutionDelayMillis;
Matthew Williams9b9244b62014-05-14 11:06:04 -07001420 mHasLateConstraint = true;
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001421 return this;
1422 }
1423
1424 /**
1425 * Set up the back-off/retry policy.
Matthew Williamsd1c06752014-08-22 14:15:28 -07001426 * This defaults to some respectable values: {30 seconds, Exponential}. We cap back-off at
1427 * 5hrs.
Christopher Tate7060b042014-06-09 19:50:00 -07001428 * Note that trying to set a backoff criteria for a job with
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001429 * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
Christopher Tate7060b042014-06-09 19:50:00 -07001430 * This is because back-off typically does not make sense for these types of jobs. See
1431 * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
1432 * for more description of the return value for the case of a job executing while in idle
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001433 * mode.
Christopher Tate7060b042014-06-09 19:50:00 -07001434 * @param initialBackoffMillis Millisecond time interval to wait initially when job has
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001435 * failed.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001436 * @see JobInfo#getInitialBackoffMillis()
1437 * @see JobInfo#getBackoffPolicy()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001438 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -06001439 public Builder setBackoffCriteria(long initialBackoffMillis,
1440 @BackoffPolicy int backoffPolicy) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001441 final long minBackoff = getMinBackoffMillis();
1442 if (initialBackoffMillis < minBackoff) {
1443 Log.w(TAG, "Requested backoff " + formatDuration(initialBackoffMillis) + " for job "
1444 + mJobId + " is too small; raising to " + formatDuration(minBackoff));
1445 initialBackoffMillis = minBackoff;
1446 }
1447
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001448 mBackoffPolicySet = true;
1449 mInitialBackoffMillis = initialBackoffMillis;
1450 mBackoffPolicy = backoffPolicy;
1451 return this;
1452 }
1453
1454 /**
Suprabh Shukla106203b2017-11-02 21:23:44 -07001455 * Setting this to true indicates that this job is important while the scheduling app
1456 * is in the foreground or on the temporary whitelist for background restrictions.
1457 * This means that the system will relax doze restrictions on this job during this time.
1458 *
1459 * Apps should use this flag only for short jobs that are essential for the app to function
1460 * properly in the foreground.
1461 *
1462 * Note that once the scheduling app is no longer whitelisted from background restrictions
1463 * and in the background, or the job failed due to unsatisfied constraints,
1464 * this job should be expected to behave like other jobs without this flag.
1465 *
1466 * @param importantWhileForeground whether to relax doze restrictions for this job when the
1467 * app is in the foreground. False by default.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001468 * @see JobInfo#isImportantWhileForeground()
Suprabh Shukla106203b2017-11-02 21:23:44 -07001469 */
1470 public Builder setImportantWhileForeground(boolean importantWhileForeground) {
1471 if (importantWhileForeground) {
1472 mFlags |= FLAG_IMPORTANT_WHILE_FOREGROUND;
1473 } else {
1474 mFlags &= (~FLAG_IMPORTANT_WHILE_FOREGROUND);
1475 }
1476 return this;
1477 }
1478
1479 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001480 * @removed
1481 * @deprecated replaced with {@link #setPrefetch(boolean)}
1482 */
1483 @Deprecated
1484 public Builder setIsPrefetch(boolean isPrefetch) {
1485 return setPrefetch(isPrefetch);
1486 }
1487
1488 /**
Jeff Sharkey9252b342018-01-19 07:58:35 +09001489 * Setting this to true indicates that this job is designed to prefetch
1490 * content that will make a material improvement to the experience of
1491 * the specific user of this device. For example, fetching top headlines
1492 * of interest to the current user.
1493 * <p>
1494 * The system may use this signal to relax the network constraints you
1495 * originally requested, such as allowing a
1496 * {@link JobInfo#NETWORK_TYPE_UNMETERED} job to run over a metered
1497 * network when there is a surplus of metered data available. The system
1498 * may also use this signal in combination with end user usage patterns
1499 * to ensure data is prefetched before the user launches your app.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001500 * @see JobInfo#isPrefetch()
Jeff Sharkey9252b342018-01-19 07:58:35 +09001501 */
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001502 public Builder setPrefetch(boolean prefetch) {
1503 if (prefetch) {
1504 mFlags |= FLAG_PREFETCH;
Jeff Sharkey9252b342018-01-19 07:58:35 +09001505 } else {
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001506 mFlags &= (~FLAG_PREFETCH);
Jeff Sharkey9252b342018-01-19 07:58:35 +09001507 }
1508 return this;
1509 }
1510
1511 /**
Jeff Sharkey30e06bb2017-04-24 11:18:03 -06001512 * Set whether or not to persist this job across device reboots.
1513 *
1514 * @param isPersisted True to indicate that the job will be written to
1515 * disk and loaded at boot.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001516 * @see JobInfo#isPersisted()
Matthew Williams900c67f2014-07-09 12:46:53 -07001517 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -06001518 @RequiresPermission(android.Manifest.permission.RECEIVE_BOOT_COMPLETED)
Matthew Williamsd1c06752014-08-22 14:15:28 -07001519 public Builder setPersisted(boolean isPersisted) {
Matthew Williams900c67f2014-07-09 12:46:53 -07001520 mIsPersisted = isPersisted;
1521 return this;
1522 }
1523
1524 /**
Christopher Tate7060b042014-06-09 19:50:00 -07001525 * @return The job object to hand to the JobScheduler. This object is immutable.
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001526 */
Christopher Tate7060b042014-06-09 19:50:00 -07001527 public JobInfo build() {
Matthew Williams9ae3dbe2014-08-21 13:47:47 -07001528 // Allow jobs with no constraints - What am I, a database?
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001529 if (!mHasEarlyConstraint && !mHasLateConstraint && mConstraintFlags == 0 &&
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001530 mNetworkRequest == null &&
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001531 mTriggerContentUris == null) {
Matthew Williamsbafeeb92014-08-08 11:51:06 -07001532 throw new IllegalArgumentException("You're trying to build a job with no " +
1533 "constraints, this is not allowed.");
1534 }
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001535 // Check that network estimates require network type
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001536 if ((mNetworkDownloadBytes > 0 || mNetworkUploadBytes > 0) && mNetworkRequest == null) {
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001537 throw new IllegalArgumentException(
1538 "Can't provide estimated network usage without requiring a network");
1539 }
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001540 // We can't serialize network specifiers
1541 if (mIsPersisted && mNetworkRequest != null
1542 && mNetworkRequest.networkCapabilities.getNetworkSpecifier() != null) {
1543 throw new IllegalArgumentException(
1544 "Network specifiers aren't supported for persistent jobs");
1545 }
Christopher Tate7060b042014-06-09 19:50:00 -07001546 // Check that a deadline was not set on a periodic job.
Dianne Hackborna47223f2017-03-30 13:49:13 -07001547 if (mIsPeriodic) {
1548 if (mMaxExecutionDelayMillis != 0L) {
1549 throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
1550 "periodic job.");
1551 }
1552 if (mMinLatencyMillis != 0L) {
1553 throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
1554 "periodic job");
1555 }
1556 if (mTriggerContentUris != null) {
1557 throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +
1558 "periodic job");
1559 }
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001560 }
Dianne Hackborna47223f2017-03-30 13:49:13 -07001561 if (mIsPersisted) {
1562 if (mTriggerContentUris != null) {
1563 throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +
1564 "persisted job");
1565 }
1566 if (!mTransientExtras.isEmpty()) {
1567 throw new IllegalArgumentException("Can't call setTransientExtras() on a " +
1568 "persisted job");
1569 }
1570 if (mClipData != null) {
1571 throw new IllegalArgumentException("Can't call setClipData() on a " +
1572 "persisted job");
1573 }
Dianne Hackbornba604732016-02-10 17:05:10 -08001574 }
Suprabh Shukla106203b2017-11-02 21:23:44 -07001575 if ((mFlags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0 && mHasEarlyConstraint) {
1576 throw new IllegalArgumentException("An important while foreground job cannot "
1577 + "have a time delay");
1578 }
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001579 if (mBackoffPolicySet && (mConstraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0) {
Christopher Tate7060b042014-06-09 19:50:00 -07001580 throw new IllegalArgumentException("An idle mode job will not respect any" +
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001581 " back-off policy, so calling setBackoffCriteria with" +
1582 " setRequiresDeviceIdle is an error.");
1583 }
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001584 return new JobInfo(this);
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001585 }
1586 }
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001587}