blob: 9baa16f2b72b828667477805bb3ddeb8a6b9c503 [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;
Mathew Inwood61e8ae62018-08-14 14:17:44 +010032import android.annotation.UnsupportedAppUsage;
Dianne Hackborna47223f2017-03-30 13:49:13 -070033import android.content.ClipData;
Christopher Tatefa380e92014-05-19 13:46:29 -070034import android.content.ComponentName;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -070035import android.net.NetworkRequest;
36import android.net.NetworkSpecifier;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080037import android.net.Uri;
Dianne Hackborn7da13d72017-04-04 17:17:35 -070038import android.os.BaseBundle;
Dianne Hackbornba604732016-02-10 17:05:10 -080039import android.os.Bundle;
Matthew Williams6e31c5c2014-04-11 15:49:16 -070040import android.os.Parcel;
41import android.os.Parcelable;
Matthew Williams3d86fd22014-05-16 18:02:17 -070042import android.os.PersistableBundle;
Shreyas Basargee96c3b72016-01-29 19:25:51 +000043import android.util.Log;
Matthew Williams6e31c5c2014-04-11 15:49:16 -070044
Jeff Sharkey30e06bb2017-04-24 11:18:03 -060045import java.lang.annotation.Retention;
46import java.lang.annotation.RetentionPolicy;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080047import java.util.ArrayList;
Paul Duffinc67663c2017-05-26 09:46:48 +010048import java.util.Arrays;
Dianne Hackborn121e1642016-06-21 20:39:02 -070049import java.util.Objects;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080050
Matthew Williams6e31c5c2014-04-11 15:49:16 -070051/**
Christopher Tate7060b042014-06-09 19:50:00 -070052 * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
Matthew Williams6e31c5c2014-04-11 15:49:16 -070053 * parameters required to schedule work against the calling application. These are constructed
Christopher Tate7060b042014-06-09 19:50:00 -070054 * using the {@link JobInfo.Builder}.
Matthew Williams9ae3dbe2014-08-21 13:47:47 -070055 * You must specify at least one sort of constraint on the JobInfo object that you are creating.
56 * The goal here is to provide the scheduler with high-level semantics about the work you want to
57 * accomplish. Doing otherwise with throw an exception in your app.
Matthew Williams6e31c5c2014-04-11 15:49:16 -070058 */
Christopher Tate7060b042014-06-09 19:50:00 -070059public class JobInfo implements Parcelable {
Shreyas Basargee96c3b72016-01-29 19:25:51 +000060 private static String TAG = "JobInfo";
Jeff Sharkey30e06bb2017-04-24 11:18:03 -060061
62 /** @hide */
63 @IntDef(prefix = { "NETWORK_TYPE_" }, value = {
64 NETWORK_TYPE_NONE,
65 NETWORK_TYPE_ANY,
66 NETWORK_TYPE_UNMETERED,
67 NETWORK_TYPE_NOT_ROAMING,
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -070068 NETWORK_TYPE_CELLULAR,
Jeff Sharkey30e06bb2017-04-24 11:18:03 -060069 })
70 @Retention(RetentionPolicy.SOURCE)
71 public @interface NetworkType {}
72
Matthew Williamsd1c06752014-08-22 14:15:28 -070073 /** Default. */
74 public static final int NETWORK_TYPE_NONE = 0;
75 /** This job requires network connectivity. */
76 public static final int NETWORK_TYPE_ANY = 1;
77 /** This job requires network connectivity that is unmetered. */
78 public static final int NETWORK_TYPE_UNMETERED = 2;
Jeff Sharkeyf07c7b92016-04-22 09:50:16 -060079 /** This job requires network connectivity that is not roaming. */
80 public static final int NETWORK_TYPE_NOT_ROAMING = 3;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -070081 /** This job requires network connectivity that is a cellular network. */
82 public static final int NETWORK_TYPE_CELLULAR = 4;
83
84 /**
85 * This job requires metered connectivity such as most cellular data
86 * networks.
87 *
88 * @deprecated Cellular networks may be unmetered, or Wi-Fi networks may be
89 * metered, so this isn't a good way of selecting a specific
90 * transport. Instead, use {@link #NETWORK_TYPE_CELLULAR} or
91 * {@link android.net.NetworkRequest.Builder#addTransportType(int)}
92 * if your job requires a specific network transport.
93 */
94 @Deprecated
95 public static final int NETWORK_TYPE_METERED = NETWORK_TYPE_CELLULAR;
Matthew Williams6e31c5c2014-04-11 15:49:16 -070096
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -060097 /** Sentinel value indicating that bytes are unknown. */
98 public static final int NETWORK_BYTES_UNKNOWN = -1;
99
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700100 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700101 * Amount of backoff a job has initially by default, in milliseconds.
Matthew Williams3d86fd22014-05-16 18:02:17 -0700102 */
Matthew Williamsd1c06752014-08-22 14:15:28 -0700103 public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 30 seconds.
104
105 /**
106 * Maximum backoff we allow for a job, in milliseconds.
107 */
108 public static final long MAX_BACKOFF_DELAY_MILLIS = 5 * 60 * 60 * 1000; // 5 hours.
109
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600110 /** @hide */
111 @IntDef(prefix = { "BACKOFF_POLICY_" }, value = {
112 BACKOFF_POLICY_LINEAR,
113 BACKOFF_POLICY_EXPONENTIAL,
114 })
115 @Retention(RetentionPolicy.SOURCE)
116 public @interface BackoffPolicy {}
117
Matthew Williamsd1c06752014-08-22 14:15:28 -0700118 /**
119 * Linearly back-off a failed job. See
120 * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}
121 * retry_time(current_time, num_failures) =
122 * current_time + initial_backoff_millis * num_failures, num_failures >= 1
123 */
124 public static final int BACKOFF_POLICY_LINEAR = 0;
125
126 /**
127 * Exponentially back-off a failed job. See
128 * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}
129 *
130 * retry_time(current_time, num_failures) =
131 * current_time + initial_backoff_millis * 2 ^ (num_failures - 1), num_failures >= 1
132 */
133 public static final int BACKOFF_POLICY_EXPONENTIAL = 1;
Matthew Williams3d86fd22014-05-16 18:02:17 -0700134
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000135 /* Minimum interval for a periodic job, in milliseconds. */
Christopher Tate10be4e92016-03-15 16:56:21 -0700136 private static final long MIN_PERIOD_MILLIS = 15 * 60 * 1000L; // 15 minutes
137
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000138 /* Minimum flex for a periodic job, in milliseconds. */
Christopher Tate10be4e92016-03-15 16:56:21 -0700139 private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
140
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700141 /**
142 * Minimum backoff interval for a job, in milliseconds
143 * @hide
144 */
145 public static final long MIN_BACKOFF_MILLIS = 10 * 1000L; // 10 seconds
Christopher Tateb2087f82017-03-29 17:42:39 -0700146
Christopher Tate10be4e92016-03-15 16:56:21 -0700147 /**
148 * Query the minimum interval allowed for periodic scheduled jobs. Attempting
149 * to declare a smaller period that this when scheduling a job will result in a
150 * job that is still periodic, but will run with this effective period.
151 *
152 * @return The minimum available interval for scheduling periodic jobs, in milliseconds.
153 */
Christopher Tatea9b4f3f2016-05-18 13:57:37 -0700154 public static final long getMinPeriodMillis() {
Christopher Tate10be4e92016-03-15 16:56:21 -0700155 return MIN_PERIOD_MILLIS;
156 }
157
158 /**
159 * Query the minimum flex time allowed for periodic scheduled jobs. Attempting
160 * to declare a shorter flex time than this when scheduling such a job will
161 * result in this amount as the effective flex time for the job.
162 *
163 * @return The minimum available flex time for scheduling periodic jobs, in milliseconds.
164 */
Christopher Tatea9b4f3f2016-05-18 13:57:37 -0700165 public static final long getMinFlexMillis() {
Christopher Tate10be4e92016-03-15 16:56:21 -0700166 return MIN_FLEX_MILLIS;
167 }
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000168
Matthew Williams3d86fd22014-05-16 18:02:17 -0700169 /**
Christopher Tateb2087f82017-03-29 17:42:39 -0700170 * Query the minimum automatic-reschedule backoff interval permitted for jobs.
171 * @hide
172 */
173 public static final long getMinBackoffMillis() {
174 return MIN_BACKOFF_MILLIS;
175 }
176
177 /**
Matthew Williams3d86fd22014-05-16 18:02:17 -0700178 * Default type of backoff.
179 * @hide
180 */
Matthew Williamsd1c06752014-08-22 14:15:28 -0700181 public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700182
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800183 /**
184 * Default of {@link #getPriority}.
185 * @hide
186 */
187 public static final int PRIORITY_DEFAULT = 0;
188
189 /**
190 * Value of {@link #getPriority} for expedited syncs.
191 * @hide
192 */
193 public static final int PRIORITY_SYNC_EXPEDITED = 10;
194
195 /**
196 * Value of {@link #getPriority} for first time initialization syncs.
197 * @hide
198 */
199 public static final int PRIORITY_SYNC_INITIALIZATION = 20;
200
201 /**
Dianne Hackborn970510b2016-02-24 16:56:42 -0800202 * Value of {@link #getPriority} for a foreground app (overrides the supplied
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800203 * JobInfo priority if it is smaller).
204 * @hide
205 */
Mathew Inwood61e8ae62018-08-14 14:17:44 +0100206 @UnsupportedAppUsage
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800207 public static final int PRIORITY_FOREGROUND_APP = 30;
208
Dianne Hackborn970510b2016-02-24 16:56:42 -0800209 /**
210 * Value of {@link #getPriority} for the current top app (overrides the supplied
211 * JobInfo priority if it is smaller).
212 * @hide
213 */
214 public static final int PRIORITY_TOP_APP = 40;
215
Dianne Hackborn807de782016-04-07 17:54:41 -0700216 /**
217 * Adjustment of {@link #getPriority} if the app has often (50% or more of the time)
218 * been running jobs.
219 * @hide
220 */
221 public static final int PRIORITY_ADJ_OFTEN_RUNNING = -40;
222
223 /**
224 * Adjustment of {@link #getPriority} if the app has always (90% or more of the time)
225 * been running jobs.
226 * @hide
227 */
228 public static final int PRIORITY_ADJ_ALWAYS_RUNNING = -80;
229
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600230 /**
231 * Indicates that the implementation of this job will be using
232 * {@link JobService#startForeground(int, android.app.Notification)} to run
233 * in the foreground.
234 * <p>
235 * When set, the internal scheduling of this job will ignore any background
236 * network restrictions for the requesting app. Note that this flag alone
237 * doesn't actually place your {@link JobService} in the foreground; you
238 * still need to post the notification yourself.
Jeff Sharkey785f4942016-07-14 10:31:15 -0600239 * <p>
240 * To use this flag, the caller must hold the
241 * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL} permission.
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600242 *
243 * @hide
244 */
Mathew Inwood61e8ae62018-08-14 14:17:44 +0100245 @UnsupportedAppUsage
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600246 public static final int FLAG_WILL_BE_FOREGROUND = 1 << 0;
247
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800248 /**
Suprabh Shukla106203b2017-11-02 21:23:44 -0700249 * Allows this job to run despite doze restrictions as long as the app is in the foreground
250 * or on the temporary whitelist
251 * @hide
252 */
253 public static final int FLAG_IMPORTANT_WHILE_FOREGROUND = 1 << 1;
254
255 /**
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800256 * @hide
257 */
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600258 public static final int FLAG_PREFETCH = 1 << 2;
Jeff Sharkey9252b342018-01-19 07:58:35 +0900259
260 /**
Makoto Onuki959acb52018-01-26 14:10:03 -0800261 * This job needs to be exempted from the app standby throttling. Only the system (UID 1000)
262 * can set it. Jobs with a time constrant must not have it.
263 *
264 * @hide
265 */
266 public static final int FLAG_EXEMPT_FROM_APP_STANDBY = 1 << 3;
267
268 /**
Jeff Sharkey9252b342018-01-19 07:58:35 +0900269 * @hide
270 */
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800271 public static final int CONSTRAINT_FLAG_CHARGING = 1 << 0;
272
273 /**
274 * @hide
275 */
276 public static final int CONSTRAINT_FLAG_BATTERY_NOT_LOW = 1 << 1;
277
278 /**
279 * @hide
280 */
281 public static final int CONSTRAINT_FLAG_DEVICE_IDLE = 1 << 2;
282
Dianne Hackborn532ea262017-03-17 17:50:55 -0700283 /**
284 * @hide
285 */
286 public static final int CONSTRAINT_FLAG_STORAGE_NOT_LOW = 1 << 3;
287
Mathew Inwood61e8ae62018-08-14 14:17:44 +0100288 @UnsupportedAppUsage
Christopher Tate7060b042014-06-09 19:50:00 -0700289 private final int jobId;
Matthew Williams3d86fd22014-05-16 18:02:17 -0700290 private final PersistableBundle extras;
Dianne Hackbornba604732016-02-10 17:05:10 -0800291 private final Bundle transientExtras;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700292 private final ClipData clipData;
293 private final int clipGrantFlags;
Mathew Inwood61e8ae62018-08-14 14:17:44 +0100294 @UnsupportedAppUsage
Matthew Williams6de79e22014-05-01 10:47:00 -0700295 private final ComponentName service;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800296 private final int constraintFlags;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800297 private final TriggerContentUri[] triggerContentUris;
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700298 private final long triggerContentUpdateDelay;
299 private final long triggerContentMaxDelay;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700300 private final boolean hasEarlyConstraint;
301 private final boolean hasLateConstraint;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700302 private final NetworkRequest networkRequest;
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600303 private final long networkDownloadBytes;
304 private final long networkUploadBytes;
Matthew Williams6de79e22014-05-01 10:47:00 -0700305 private final long minLatencyMillis;
306 private final long maxExecutionDelayMillis;
307 private final boolean isPeriodic;
Matthew Williams900c67f2014-07-09 12:46:53 -0700308 private final boolean isPersisted;
Matthew Williams6de79e22014-05-01 10:47:00 -0700309 private final long intervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000310 private final long flexMillis;
Matthew Williams6de79e22014-05-01 10:47:00 -0700311 private final long initialBackoffMillis;
312 private final int backoffPolicy;
Shreyas Basarge5db09082016-01-07 13:38:29 +0000313 private final int priority;
Mathew Inwood61e8ae62018-08-14 14:17:44 +0100314 @UnsupportedAppUsage
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600315 private final int flags;
Matthew Williams6de79e22014-05-01 10:47:00 -0700316
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700317 /**
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700318 * Unique job id associated with this application (uid). This is the same job ID
319 * you supplied in the {@link Builder} constructor.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700320 */
Matthew Williams9b9244b62014-05-14 11:06:04 -0700321 public int getId() {
Christopher Tate7060b042014-06-09 19:50:00 -0700322 return jobId;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700323 }
324
325 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600326 * @see JobInfo.Builder#setExtras(PersistableBundle)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700327 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700328 public @NonNull PersistableBundle getExtras() {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700329 return extras;
330 }
331
332 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600333 * @see JobInfo.Builder#setTransientExtras(Bundle)
Dianne Hackbornba604732016-02-10 17:05:10 -0800334 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700335 public @NonNull Bundle getTransientExtras() {
Dianne Hackbornba604732016-02-10 17:05:10 -0800336 return transientExtras;
337 }
338
339 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600340 * @see JobInfo.Builder#setClipData(ClipData, int)
Dianne Hackborna47223f2017-03-30 13:49:13 -0700341 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700342 public @Nullable ClipData getClipData() {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700343 return clipData;
344 }
345
346 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600347 * @see JobInfo.Builder#setClipData(ClipData, int)
Dianne Hackborna47223f2017-03-30 13:49:13 -0700348 */
349 public int getClipGrantFlags() {
350 return clipGrantFlags;
351 }
352
353 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700354 * Name of the service endpoint that will be called back into by the JobScheduler.
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700355 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700356 public @NonNull ComponentName getService() {
Matthew Williams6de79e22014-05-01 10:47:00 -0700357 return service;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700358 }
359
Shreyas Basarge5db09082016-01-07 13:38:29 +0000360 /** @hide */
361 public int getPriority() {
362 return priority;
363 }
364
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600365 /** @hide */
366 public int getFlags() {
367 return flags;
368 }
369
Makoto Onuki959acb52018-01-26 14:10:03 -0800370 /** @hide */
371 public boolean isExemptedFromAppStandby() {
Makoto Onuki2b5811a2018-02-08 11:09:42 -0800372 return ((flags & FLAG_EXEMPT_FROM_APP_STANDBY) != 0) && !isPeriodic();
Makoto Onuki959acb52018-01-26 14:10:03 -0800373 }
374
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700375 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600376 * @see JobInfo.Builder#setRequiresCharging(boolean)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700377 */
378 public boolean isRequireCharging() {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800379 return (constraintFlags & CONSTRAINT_FLAG_CHARGING) != 0;
380 }
381
382 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600383 * @see JobInfo.Builder#setRequiresBatteryNotLow(boolean)
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800384 */
385 public boolean isRequireBatteryNotLow() {
386 return (constraintFlags & CONSTRAINT_FLAG_BATTERY_NOT_LOW) != 0;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700387 }
388
389 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600390 * @see JobInfo.Builder#setRequiresDeviceIdle(boolean)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700391 */
392 public boolean isRequireDeviceIdle() {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800393 return (constraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0;
394 }
395
396 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600397 * @see JobInfo.Builder#setRequiresStorageNotLow(boolean)
Dianne Hackborn532ea262017-03-17 17:50:55 -0700398 */
399 public boolean isRequireStorageNotLow() {
400 return (constraintFlags & CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0;
401 }
402
403 /**
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800404 * @hide
405 */
406 public int getConstraintFlags() {
407 return constraintFlags;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700408 }
409
410 /**
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800411 * Which content: URIs must change for the job to be scheduled. Returns null
412 * if there are none required.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600413 * @see JobInfo.Builder#addTriggerContentUri(TriggerContentUri)
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800414 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700415 public @Nullable TriggerContentUri[] getTriggerContentUris() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800416 return triggerContentUris;
417 }
418
419 /**
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700420 * When triggering on content URI changes, this is the delay from when a change
421 * is detected until the job is scheduled.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600422 * @see JobInfo.Builder#setTriggerContentUpdateDelay(long)
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700423 */
424 public long getTriggerContentUpdateDelay() {
425 return triggerContentUpdateDelay;
426 }
427
428 /**
429 * When triggering on content URI changes, this is the maximum delay we will
430 * use before scheduling the job.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600431 * @see JobInfo.Builder#setTriggerContentMaxDelay(long)
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700432 */
433 public long getTriggerContentMaxDelay() {
434 return triggerContentMaxDelay;
435 }
436
437 /**
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700438 * Return the basic description of the kind of network this job requires.
439 *
440 * @deprecated This method attempts to map {@link #getRequiredNetwork()}
441 * into the set of simple constants, which results in a loss of
442 * fidelity. Callers should move to using
443 * {@link #getRequiredNetwork()} directly.
444 * @see Builder#setRequiredNetworkType(int)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700445 */
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700446 @Deprecated
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600447 public @NetworkType int getNetworkType() {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700448 if (networkRequest == null) {
449 return NETWORK_TYPE_NONE;
450 } else if (networkRequest.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
451 return NETWORK_TYPE_UNMETERED;
452 } else if (networkRequest.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING)) {
453 return NETWORK_TYPE_NOT_ROAMING;
454 } else if (networkRequest.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
455 return NETWORK_TYPE_CELLULAR;
456 } else {
457 return NETWORK_TYPE_ANY;
458 }
459 }
460
461 /**
462 * Return the detailed description of the kind of network this job requires,
463 * or {@code null} if no specific kind of network is required.
464 *
465 * @see Builder#setRequiredNetwork(NetworkRequest)
466 */
467 public @Nullable NetworkRequest getRequiredNetwork() {
468 return networkRequest;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700469 }
470
471 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600472 * @deprecated replaced by {@link #getEstimatedNetworkDownloadBytes()} and
473 * {@link #getEstimatedNetworkUploadBytes()}.
474 * @removed
475 */
476 @Deprecated
477 public @BytesLong long getEstimatedNetworkBytes() {
478 if (networkDownloadBytes == NETWORK_BYTES_UNKNOWN
479 && networkUploadBytes == NETWORK_BYTES_UNKNOWN) {
480 return NETWORK_BYTES_UNKNOWN;
481 } else if (networkDownloadBytes == NETWORK_BYTES_UNKNOWN) {
482 return networkUploadBytes;
483 } else if (networkUploadBytes == NETWORK_BYTES_UNKNOWN) {
484 return networkDownloadBytes;
485 } else {
486 return networkDownloadBytes + networkUploadBytes;
487 }
488 }
489
490 /**
491 * Return the estimated size of download traffic that will be performed by
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600492 * this job, in bytes.
493 *
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600494 * @return Estimated size of download traffic, or
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600495 * {@link #NETWORK_BYTES_UNKNOWN} when unknown.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600496 * @see Builder#setEstimatedNetworkBytes(long, long)
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600497 */
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600498 public @BytesLong long getEstimatedNetworkDownloadBytes() {
499 return networkDownloadBytes;
500 }
501
502 /**
503 * Return the estimated size of upload traffic that will be performed by
504 * this job, in bytes.
505 *
506 * @return Estimated size of upload traffic, or
507 * {@link #NETWORK_BYTES_UNKNOWN} when unknown.
508 * @see Builder#setEstimatedNetworkBytes(long, long)
509 */
510 public @BytesLong long getEstimatedNetworkUploadBytes() {
511 return networkUploadBytes;
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600512 }
513
514 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700515 * Set for a job that does not recur periodically, to specify a delay after which the job
516 * will be eligible for execution. This value is not set if the job recurs periodically.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600517 * @see JobInfo.Builder#setMinimumLatency(long)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700518 */
519 public long getMinLatencyMillis() {
520 return minLatencyMillis;
521 }
522
523 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600524 * @see JobInfo.Builder#setOverrideDeadline(long)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700525 */
526 public long getMaxExecutionDelayMillis() {
527 return maxExecutionDelayMillis;
528 }
529
530 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700531 * Track whether this job will repeat with a given period.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600532 * @see JobInfo.Builder#setPeriodic(long)
533 * @see JobInfo.Builder#setPeriodic(long, long)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700534 */
535 public boolean isPeriodic() {
536 return isPeriodic;
537 }
538
539 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600540 * @see JobInfo.Builder#setPersisted(boolean)
Matthew Williams900c67f2014-07-09 12:46:53 -0700541 */
542 public boolean isPersisted() {
543 return isPersisted;
544 }
545
546 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700547 * Set to the interval between occurrences of this job. This value is <b>not</b> set if the
548 * job does not recur periodically.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600549 * @see JobInfo.Builder#setPeriodic(long)
550 * @see JobInfo.Builder#setPeriodic(long, long)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700551 */
552 public long getIntervalMillis() {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700553 return intervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000554 }
555
556 /**
Shreyas Basarge9e6d5882016-04-12 10:59:07 +0100557 * Flex time for this job. Only valid if this is a periodic job. The job can
558 * execute at any time in a window of flex length at the end of the period.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600559 * @see JobInfo.Builder#setPeriodic(long)
560 * @see JobInfo.Builder#setPeriodic(long, long)
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000561 */
562 public long getFlexMillis() {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700563 return flexMillis;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700564 }
565
566 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700567 * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
568 * will be increased depending on the backoff policy specified at job creation time. Defaults
Dianne Hackbornbfc23312017-05-11 11:53:24 -0700569 * to 30 seconds, minimum is currently 10 seconds.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600570 * @see JobInfo.Builder#setBackoffCriteria(long, int)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700571 */
572 public long getInitialBackoffMillis() {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700573 return initialBackoffMillis;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700574 }
575
576 /**
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600577 * Return the backoff policy of this job.
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600578 * @see JobInfo.Builder#setBackoffCriteria(long, int)
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700579 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600580 public @BackoffPolicy int getBackoffPolicy() {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700581 return backoffPolicy;
582 }
583
Matthew Williams9b9244b62014-05-14 11:06:04 -0700584 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600585 * @see JobInfo.Builder#setImportantWhileForeground(boolean)
586 */
587 public boolean isImportantWhileForeground() {
588 return (flags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0;
589 }
590
591 /**
592 * @see JobInfo.Builder#setPrefetch(boolean)
593 */
594 public boolean isPrefetch() {
595 return (flags & FLAG_PREFETCH) != 0;
596 }
597
598 /**
Matthew Williams9b9244b62014-05-14 11:06:04 -0700599 * User can specify an early constraint of 0L, which is valid, so we keep track of whether the
600 * function was called at all.
601 * @hide
602 */
603 public boolean hasEarlyConstraint() {
604 return hasEarlyConstraint;
605 }
606
607 /**
608 * User can specify a late constraint of 0L, which is valid, so we keep track of whether the
609 * function was called at all.
610 * @hide
611 */
612 public boolean hasLateConstraint() {
613 return hasLateConstraint;
614 }
615
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700616 private static boolean kindofEqualsBundle(BaseBundle a, BaseBundle b) {
617 return (a == b) || (a != null && a.kindofEquals(b));
618 }
619
620 @Override
621 public boolean equals(Object o) {
622 if (!(o instanceof JobInfo)) {
623 return false;
624 }
625 JobInfo j = (JobInfo) o;
626 if (jobId != j.jobId) {
627 return false;
628 }
629 // XXX won't be correct if one is parcelled and the other not.
630 if (!kindofEqualsBundle(extras, j.extras)) {
631 return false;
632 }
633 // XXX won't be correct if one is parcelled and the other not.
634 if (!kindofEqualsBundle(transientExtras, j.transientExtras)) {
635 return false;
636 }
637 // XXX for now we consider two different clip data objects to be different,
638 // regardless of whether their contents are the same.
639 if (clipData != j.clipData) {
640 return false;
641 }
642 if (clipGrantFlags != j.clipGrantFlags) {
643 return false;
644 }
645 if (!Objects.equals(service, j.service)) {
646 return false;
647 }
648 if (constraintFlags != j.constraintFlags) {
649 return false;
650 }
Paul Duffinc67663c2017-05-26 09:46:48 +0100651 if (!Arrays.equals(triggerContentUris, j.triggerContentUris)) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700652 return false;
653 }
654 if (triggerContentUpdateDelay != j.triggerContentUpdateDelay) {
655 return false;
656 }
657 if (triggerContentMaxDelay != j.triggerContentMaxDelay) {
658 return false;
659 }
660 if (hasEarlyConstraint != j.hasEarlyConstraint) {
661 return false;
662 }
663 if (hasLateConstraint != j.hasLateConstraint) {
664 return false;
665 }
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700666 if (!Objects.equals(networkRequest, j.networkRequest)) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700667 return false;
668 }
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600669 if (networkDownloadBytes != j.networkDownloadBytes) {
670 return false;
671 }
672 if (networkUploadBytes != j.networkUploadBytes) {
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -0600673 return false;
674 }
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700675 if (minLatencyMillis != j.minLatencyMillis) {
676 return false;
677 }
678 if (maxExecutionDelayMillis != j.maxExecutionDelayMillis) {
679 return false;
680 }
681 if (isPeriodic != j.isPeriodic) {
682 return false;
683 }
684 if (isPersisted != j.isPersisted) {
685 return false;
686 }
687 if (intervalMillis != j.intervalMillis) {
688 return false;
689 }
690 if (flexMillis != j.flexMillis) {
691 return false;
692 }
693 if (initialBackoffMillis != j.initialBackoffMillis) {
694 return false;
695 }
696 if (backoffPolicy != j.backoffPolicy) {
697 return false;
698 }
699 if (priority != j.priority) {
700 return false;
701 }
702 if (flags != j.flags) {
703 return false;
704 }
705 return true;
706 }
707
708 @Override
709 public int hashCode() {
710 int hashCode = jobId;
711 if (extras != null) {
Paul Duffinc67663c2017-05-26 09:46:48 +0100712 hashCode = 31 * hashCode + extras.hashCode();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700713 }
714 if (transientExtras != null) {
Paul Duffinc67663c2017-05-26 09:46:48 +0100715 hashCode = 31 * hashCode + transientExtras.hashCode();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700716 }
717 if (clipData != null) {
Paul Duffinc67663c2017-05-26 09:46:48 +0100718 hashCode = 31 * hashCode + clipData.hashCode();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700719 }
720 hashCode = 31*hashCode + clipGrantFlags;
721 if (service != null) {
Paul Duffinc67663c2017-05-26 09:46:48 +0100722 hashCode = 31 * hashCode + service.hashCode();
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700723 }
Paul Duffinc67663c2017-05-26 09:46:48 +0100724 hashCode = 31 * hashCode + constraintFlags;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700725 if (triggerContentUris != null) {
Paul Duffinc67663c2017-05-26 09:46:48 +0100726 hashCode = 31 * hashCode + Arrays.hashCode(triggerContentUris);
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700727 }
Paul Duffinc67663c2017-05-26 09:46:48 +0100728 hashCode = 31 * hashCode + Long.hashCode(triggerContentUpdateDelay);
729 hashCode = 31 * hashCode + Long.hashCode(triggerContentMaxDelay);
730 hashCode = 31 * hashCode + Boolean.hashCode(hasEarlyConstraint);
731 hashCode = 31 * hashCode + Boolean.hashCode(hasLateConstraint);
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700732 if (networkRequest != null) {
733 hashCode = 31 * hashCode + networkRequest.hashCode();
734 }
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600735 hashCode = 31 * hashCode + Long.hashCode(networkDownloadBytes);
736 hashCode = 31 * hashCode + Long.hashCode(networkUploadBytes);
Paul Duffinc67663c2017-05-26 09:46:48 +0100737 hashCode = 31 * hashCode + Long.hashCode(minLatencyMillis);
738 hashCode = 31 * hashCode + Long.hashCode(maxExecutionDelayMillis);
739 hashCode = 31 * hashCode + Boolean.hashCode(isPeriodic);
740 hashCode = 31 * hashCode + Boolean.hashCode(isPersisted);
741 hashCode = 31 * hashCode + Long.hashCode(intervalMillis);
742 hashCode = 31 * hashCode + Long.hashCode(flexMillis);
743 hashCode = 31 * hashCode + Long.hashCode(initialBackoffMillis);
744 hashCode = 31 * hashCode + backoffPolicy;
745 hashCode = 31 * hashCode + priority;
746 hashCode = 31 * hashCode + flags;
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700747 return hashCode;
748 }
749
Christopher Tate7060b042014-06-09 19:50:00 -0700750 private JobInfo(Parcel in) {
751 jobId = in.readInt();
Matthew Williams3d86fd22014-05-16 18:02:17 -0700752 extras = in.readPersistableBundle();
Dianne Hackbornba604732016-02-10 17:05:10 -0800753 transientExtras = in.readBundle();
Dianne Hackborna47223f2017-03-30 13:49:13 -0700754 if (in.readInt() != 0) {
755 clipData = ClipData.CREATOR.createFromParcel(in);
756 clipGrantFlags = in.readInt();
757 } else {
758 clipData = null;
759 clipGrantFlags = 0;
760 }
Matthew Williamseffacfa2014-06-05 20:56:40 -0700761 service = in.readParcelable(null);
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800762 constraintFlags = in.readInt();
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800763 triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR);
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700764 triggerContentUpdateDelay = in.readLong();
765 triggerContentMaxDelay = in.readLong();
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700766 if (in.readInt() != 0) {
767 networkRequest = NetworkRequest.CREATOR.createFromParcel(in);
768 } else {
769 networkRequest = null;
770 }
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600771 networkDownloadBytes = in.readLong();
772 networkUploadBytes = in.readLong();
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700773 minLatencyMillis = in.readLong();
774 maxExecutionDelayMillis = in.readLong();
775 isPeriodic = in.readInt() == 1;
Matthew Williams900c67f2014-07-09 12:46:53 -0700776 isPersisted = in.readInt() == 1;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700777 intervalMillis = in.readLong();
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000778 flexMillis = in.readLong();
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700779 initialBackoffMillis = in.readLong();
780 backoffPolicy = in.readInt();
Matthew Williams9b9244b62014-05-14 11:06:04 -0700781 hasEarlyConstraint = in.readInt() == 1;
782 hasLateConstraint = in.readInt() == 1;
Shreyas Basarge5db09082016-01-07 13:38:29 +0000783 priority = in.readInt();
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600784 flags = in.readInt();
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700785 }
786
Christopher Tate7060b042014-06-09 19:50:00 -0700787 private JobInfo(JobInfo.Builder b) {
788 jobId = b.mJobId;
Dianne Hackborn2510b372017-03-03 17:01:38 -0800789 extras = b.mExtras.deepCopy();
790 transientExtras = b.mTransientExtras.deepCopy();
Dianne Hackborna47223f2017-03-30 13:49:13 -0700791 clipData = b.mClipData;
792 clipGrantFlags = b.mClipGrantFlags;
Christopher Tate7060b042014-06-09 19:50:00 -0700793 service = b.mJobService;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800794 constraintFlags = b.mConstraintFlags;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800795 triggerContentUris = b.mTriggerContentUris != null
796 ? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()])
797 : null;
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700798 triggerContentUpdateDelay = b.mTriggerContentUpdateDelay;
799 triggerContentMaxDelay = b.mTriggerContentMaxDelay;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700800 networkRequest = b.mNetworkRequest;
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600801 networkDownloadBytes = b.mNetworkDownloadBytes;
802 networkUploadBytes = b.mNetworkUploadBytes;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700803 minLatencyMillis = b.mMinLatencyMillis;
804 maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
805 isPeriodic = b.mIsPeriodic;
Matthew Williams900c67f2014-07-09 12:46:53 -0700806 isPersisted = b.mIsPersisted;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700807 intervalMillis = b.mIntervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000808 flexMillis = b.mFlexMillis;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700809 initialBackoffMillis = b.mInitialBackoffMillis;
810 backoffPolicy = b.mBackoffPolicy;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700811 hasEarlyConstraint = b.mHasEarlyConstraint;
812 hasLateConstraint = b.mHasLateConstraint;
Shreyas Basarge5db09082016-01-07 13:38:29 +0000813 priority = b.mPriority;
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600814 flags = b.mFlags;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700815 }
816
817 @Override
818 public int describeContents() {
819 return 0;
820 }
821
822 @Override
823 public void writeToParcel(Parcel out, int flags) {
Christopher Tate7060b042014-06-09 19:50:00 -0700824 out.writeInt(jobId);
Matthew Williams3d86fd22014-05-16 18:02:17 -0700825 out.writePersistableBundle(extras);
Dianne Hackbornba604732016-02-10 17:05:10 -0800826 out.writeBundle(transientExtras);
Dianne Hackborna47223f2017-03-30 13:49:13 -0700827 if (clipData != null) {
828 out.writeInt(1);
829 clipData.writeToParcel(out, flags);
830 out.writeInt(clipGrantFlags);
831 } else {
832 out.writeInt(0);
833 }
Matthew Williamseffacfa2014-06-05 20:56:40 -0700834 out.writeParcelable(service, flags);
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800835 out.writeInt(constraintFlags);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800836 out.writeTypedArray(triggerContentUris, flags);
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700837 out.writeLong(triggerContentUpdateDelay);
838 out.writeLong(triggerContentMaxDelay);
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700839 if (networkRequest != null) {
840 out.writeInt(1);
841 networkRequest.writeToParcel(out, flags);
842 } else {
843 out.writeInt(0);
844 }
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600845 out.writeLong(networkDownloadBytes);
846 out.writeLong(networkUploadBytes);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700847 out.writeLong(minLatencyMillis);
848 out.writeLong(maxExecutionDelayMillis);
849 out.writeInt(isPeriodic ? 1 : 0);
Matthew Williams900c67f2014-07-09 12:46:53 -0700850 out.writeInt(isPersisted ? 1 : 0);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700851 out.writeLong(intervalMillis);
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000852 out.writeLong(flexMillis);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700853 out.writeLong(initialBackoffMillis);
854 out.writeInt(backoffPolicy);
Matthew Williams9b9244b62014-05-14 11:06:04 -0700855 out.writeInt(hasEarlyConstraint ? 1 : 0);
856 out.writeInt(hasLateConstraint ? 1 : 0);
Shreyas Basarge5db09082016-01-07 13:38:29 +0000857 out.writeInt(priority);
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600858 out.writeInt(this.flags);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700859 }
860
Christopher Tate7060b042014-06-09 19:50:00 -0700861 public static final Creator<JobInfo> CREATOR = new Creator<JobInfo>() {
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700862 @Override
Christopher Tate7060b042014-06-09 19:50:00 -0700863 public JobInfo createFromParcel(Parcel in) {
864 return new JobInfo(in);
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700865 }
866
867 @Override
Christopher Tate7060b042014-06-09 19:50:00 -0700868 public JobInfo[] newArray(int size) {
869 return new JobInfo[size];
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700870 }
871 };
872
Matthew Williamsee410da2014-07-25 11:30:40 -0700873 @Override
874 public String toString() {
875 return "(job:" + jobId + "/" + service.flattenToShortString() + ")";
876 }
877
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800878 /**
879 * Information about a content URI modification that a job would like to
880 * trigger on.
881 */
882 public static final class TriggerContentUri implements Parcelable {
883 private final Uri mUri;
884 private final int mFlags;
885
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600886 /** @hide */
887 @Retention(RetentionPolicy.SOURCE)
888 @IntDef(flag = true, prefix = { "FLAG_" }, value = {
889 FLAG_NOTIFY_FOR_DESCENDANTS,
890 })
891 public @interface Flags { }
892
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800893 /**
894 * Flag for trigger: also trigger if any descendants of the given URI change.
895 * Corresponds to the <var>notifyForDescendants</var> of
896 * {@link android.content.ContentResolver#registerContentObserver}.
897 */
898 public static final int FLAG_NOTIFY_FOR_DESCENDANTS = 1<<0;
899
900 /**
901 * Create a new trigger description.
902 * @param uri The URI to observe. Must be non-null.
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600903 * @param flags Flags for the observer.
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800904 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600905 public TriggerContentUri(@NonNull Uri uri, @Flags int flags) {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800906 mUri = uri;
907 mFlags = flags;
908 }
909
910 /**
911 * Return the Uri this trigger was created for.
912 */
913 public Uri getUri() {
914 return mUri;
915 }
916
917 /**
918 * Return the flags supplied for the trigger.
919 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600920 public @Flags int getFlags() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800921 return mFlags;
922 }
923
Dianne Hackborn121e1642016-06-21 20:39:02 -0700924 @Override
925 public boolean equals(Object o) {
926 if (!(o instanceof TriggerContentUri)) {
927 return false;
928 }
929 TriggerContentUri t = (TriggerContentUri) o;
930 return Objects.equals(t.mUri, mUri) && t.mFlags == mFlags;
931 }
932
933 @Override
934 public int hashCode() {
935 return (mUri == null ? 0 : mUri.hashCode()) ^ mFlags;
936 }
937
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800938 private TriggerContentUri(Parcel in) {
939 mUri = Uri.CREATOR.createFromParcel(in);
940 mFlags = in.readInt();
941 }
942
943 @Override
944 public int describeContents() {
945 return 0;
946 }
947
948 @Override
949 public void writeToParcel(Parcel out, int flags) {
950 mUri.writeToParcel(out, flags);
951 out.writeInt(mFlags);
952 }
953
954 public static final Creator<TriggerContentUri> CREATOR = new Creator<TriggerContentUri>() {
955 @Override
956 public TriggerContentUri createFromParcel(Parcel in) {
957 return new TriggerContentUri(in);
958 }
959
960 @Override
961 public TriggerContentUri[] newArray(int size) {
962 return new TriggerContentUri[size];
963 }
964 };
965 }
966
Christopher Tate7060b042014-06-09 19:50:00 -0700967 /** Builder class for constructing {@link JobInfo} objects. */
Matthew Williams9b9244b62014-05-14 11:06:04 -0700968 public static final class Builder {
Dianne Hackborne9a988c2016-05-27 17:59:40 -0700969 private final int mJobId;
970 private final ComponentName mJobService;
Matthew Williams3d86fd22014-05-16 18:02:17 -0700971 private PersistableBundle mExtras = PersistableBundle.EMPTY;
Dianne Hackbornba604732016-02-10 17:05:10 -0800972 private Bundle mTransientExtras = Bundle.EMPTY;
Dianne Hackborna47223f2017-03-30 13:49:13 -0700973 private ClipData mClipData;
974 private int mClipGrantFlags;
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800975 private int mPriority = PRIORITY_DEFAULT;
Jeff Sharkey1b6519b2016-04-28 15:33:18 -0600976 private int mFlags;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700977 // Requirements.
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800978 private int mConstraintFlags;
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -0700979 private NetworkRequest mNetworkRequest;
Jeff Sharkey8474ca02018-03-26 19:10:02 -0600980 private long mNetworkDownloadBytes = NETWORK_BYTES_UNKNOWN;
981 private long mNetworkUploadBytes = NETWORK_BYTES_UNKNOWN;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800982 private ArrayList<TriggerContentUri> mTriggerContentUris;
Dianne Hackborn8db0fc12016-04-12 13:48:25 -0700983 private long mTriggerContentUpdateDelay = -1;
984 private long mTriggerContentMaxDelay = -1;
Matthew Williams900c67f2014-07-09 12:46:53 -0700985 private boolean mIsPersisted;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700986 // One-off parameters.
987 private long mMinLatencyMillis;
988 private long mMaxExecutionDelayMillis;
989 // Periodic parameters.
990 private boolean mIsPeriodic;
Matthew Williams9b9244b62014-05-14 11:06:04 -0700991 private boolean mHasEarlyConstraint;
992 private boolean mHasLateConstraint;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700993 private long mIntervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +0000994 private long mFlexMillis;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700995 // Back-off parameters.
Matthew Williams3d86fd22014-05-16 18:02:17 -0700996 private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS;
997 private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY;
Matthew Williams6e31c5c2014-04-11 15:49:16 -0700998 /** Easy way to track whether the client has tried to set a back-off policy. */
999 private boolean mBackoffPolicySet = false;
1000
1001 /**
Dianne Hackborne9a988c2016-05-27 17:59:40 -07001002 * Initialize a new Builder to construct a {@link JobInfo}.
1003 *
Christopher Tate7060b042014-06-09 19:50:00 -07001004 * @param jobId Application-provided id for this job. Subsequent calls to cancel, or
Dianne Hackborne9a988c2016-05-27 17:59:40 -07001005 * jobs created with the same jobId, will update the pre-existing job with
1006 * the same id. This ID must be unique across all clients of the same uid
1007 * (not just the same package). You will want to make sure this is a stable
1008 * id across app updates, so probably not based on a resource ID.
Christopher Tate7060b042014-06-09 19:50:00 -07001009 * @param jobService The endpoint that you implement that will receive the callback from the
Dianne Hackborne9a988c2016-05-27 17:59:40 -07001010 * JobScheduler.
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001011 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001012 public Builder(int jobId, @NonNull ComponentName jobService) {
Christopher Tate7060b042014-06-09 19:50:00 -07001013 mJobService = jobService;
1014 mJobId = jobId;
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001015 }
1016
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001017 /** @hide */
Mathew Inwood61e8ae62018-08-14 14:17:44 +01001018 @UnsupportedAppUsage
Shreyas Basarge5db09082016-01-07 13:38:29 +00001019 public Builder setPriority(int priority) {
1020 mPriority = priority;
1021 return this;
1022 }
1023
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001024 /** @hide */
Mathew Inwood61e8ae62018-08-14 14:17:44 +01001025 @UnsupportedAppUsage
Jeff Sharkey1b6519b2016-04-28 15:33:18 -06001026 public Builder setFlags(int flags) {
1027 mFlags = flags;
1028 return this;
1029 }
1030
Shreyas Basarge5db09082016-01-07 13:38:29 +00001031 /**
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001032 * Set optional extras. This is persisted, so we only allow primitive types.
1033 * @param extras Bundle containing extras you want the scheduler to hold on to for you.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001034 * @see JobInfo#getExtras()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001035 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001036 public Builder setExtras(@NonNull PersistableBundle extras) {
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001037 mExtras = extras;
1038 return this;
1039 }
1040
1041 /**
Dianne Hackborn28d1b662017-04-21 14:17:23 -07001042 * Set optional transient extras.
1043 *
1044 * <p>Because setting this property is not compatible with persisted
1045 * jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
1046 * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
1047 *
Dianne Hackbornba604732016-02-10 17:05:10 -08001048 * @param extras Bundle containing extras you want the scheduler to hold on to for you.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001049 * @see JobInfo#getTransientExtras()
Dianne Hackbornba604732016-02-10 17:05:10 -08001050 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001051 public Builder setTransientExtras(@NonNull Bundle extras) {
Dianne Hackbornba604732016-02-10 17:05:10 -08001052 mTransientExtras = extras;
1053 return this;
1054 }
1055
1056 /**
Dianne Hackborna47223f2017-03-30 13:49:13 -07001057 * Set a {@link ClipData} associated with this Job.
1058 *
1059 * <p>The main purpose of providing a ClipData is to allow granting of
1060 * URI permissions for data associated with the clip. The exact kind
1061 * of permission grant to perform is specified through <var>grantFlags</var>.
1062 *
1063 * <p>If the ClipData contains items that are Intents, any
1064 * grant flags in those Intents will be ignored. Only flags provided as an argument
1065 * to this method are respected, and will be applied to all Uri or
1066 * Intent items in the clip (or sub-items of the clip).
1067 *
1068 * <p>Because setting this property is not compatible with persisted
1069 * jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
1070 * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
1071 *
1072 * @param clip The new clip to set. May be null to clear the current clip.
1073 * @param grantFlags The desired permissions to grant for any URIs. This should be
1074 * a combination of {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION},
1075 * {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, and
1076 * {@link android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION}.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001077 * @see JobInfo#getClipData()
1078 * @see JobInfo#getClipGrantFlags()
Dianne Hackborna47223f2017-03-30 13:49:13 -07001079 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -07001080 public Builder setClipData(@Nullable ClipData clip, int grantFlags) {
Dianne Hackborna47223f2017-03-30 13:49:13 -07001081 mClipData = clip;
1082 mClipGrantFlags = grantFlags;
1083 return this;
1084 }
1085
1086 /**
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001087 * Set basic description of the kind of network your job requires. If
1088 * you need more precise control over network capabilities, see
1089 * {@link #setRequiredNetwork(NetworkRequest)}.
1090 * <p>
1091 * If your job doesn't need a network connection, you don't need to call
1092 * this method, as the default value is {@link #NETWORK_TYPE_NONE}.
1093 * <p>
1094 * Calling this method defines network as a strict requirement for your
1095 * job. If the network requested is not available your job will never
1096 * run. See {@link #setOverrideDeadline(long)} to change this behavior.
1097 * Calling this method will override any requirements previously defined
1098 * by {@link #setRequiredNetwork(NetworkRequest)}; you typically only
1099 * want to call one of these methods.
Jeff Sharkey76a02412017-10-24 16:55:04 -06001100 * <p class="note">
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001101 * When your job executes in
Jeff Sharkey76a02412017-10-24 16:55:04 -06001102 * {@link JobService#onStartJob(JobParameters)}, be sure to use the
1103 * specific network returned by {@link JobParameters#getNetwork()},
1104 * otherwise you'll use the default network which may not meet this
1105 * constraint.
1106 *
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001107 * @see #setRequiredNetwork(NetworkRequest)
1108 * @see JobInfo#getNetworkType()
Jeff Sharkey76a02412017-10-24 16:55:04 -06001109 * @see JobParameters#getNetwork()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001110 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -06001111 public Builder setRequiredNetworkType(@NetworkType int networkType) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001112 if (networkType == NETWORK_TYPE_NONE) {
1113 return setRequiredNetwork(null);
1114 } else {
1115 final NetworkRequest.Builder builder = new NetworkRequest.Builder();
1116
1117 // All types require validated Internet
1118 builder.addCapability(NET_CAPABILITY_INTERNET);
1119 builder.addCapability(NET_CAPABILITY_VALIDATED);
1120 builder.removeCapability(NET_CAPABILITY_NOT_VPN);
1121
1122 if (networkType == NETWORK_TYPE_ANY) {
1123 // No other capabilities
1124 } else if (networkType == NETWORK_TYPE_UNMETERED) {
1125 builder.addCapability(NET_CAPABILITY_NOT_METERED);
1126 } else if (networkType == NETWORK_TYPE_NOT_ROAMING) {
1127 builder.addCapability(NET_CAPABILITY_NOT_ROAMING);
1128 } else if (networkType == NETWORK_TYPE_CELLULAR) {
1129 builder.addTransportType(TRANSPORT_CELLULAR);
1130 }
1131
1132 return setRequiredNetwork(builder.build());
1133 }
1134 }
1135
1136 /**
1137 * Set detailed description of the kind of network your job requires.
1138 * <p>
1139 * If your job doesn't need a network connection, you don't need to call
1140 * this method, as the default is {@code null}.
1141 * <p>
1142 * Calling this method defines network as a strict requirement for your
1143 * job. If the network requested is not available your job will never
1144 * run. See {@link #setOverrideDeadline(long)} to change this behavior.
1145 * Calling this method will override any requirements previously defined
1146 * by {@link #setRequiredNetworkType(int)}; you typically only want to
1147 * call one of these methods.
1148 * <p class="note">
1149 * When your job executes in
1150 * {@link JobService#onStartJob(JobParameters)}, be sure to use the
1151 * specific network returned by {@link JobParameters#getNetwork()},
1152 * otherwise you'll use the default network which may not meet this
1153 * constraint.
1154 *
1155 * @param networkRequest The detailed description of the kind of network
1156 * this job requires, or {@code null} if no specific kind of
1157 * network is required. Defining a {@link NetworkSpecifier}
1158 * is only supported for jobs that aren't persisted.
1159 * @see #setRequiredNetworkType(int)
1160 * @see JobInfo#getRequiredNetwork()
1161 * @see JobParameters#getNetwork()
1162 */
1163 public Builder setRequiredNetwork(@Nullable NetworkRequest networkRequest) {
1164 mNetworkRequest = networkRequest;
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001165 return this;
1166 }
1167
Christopher Tate7060b042014-06-09 19:50:00 -07001168 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001169 * @deprecated replaced by
1170 * {@link #setEstimatedNetworkBytes(long, long)}.
1171 * @removed
1172 */
1173 @Deprecated
1174 public Builder setEstimatedNetworkBytes(@BytesLong long networkBytes) {
1175 return setEstimatedNetworkBytes(networkBytes, NETWORK_BYTES_UNKNOWN);
1176 }
1177
1178 /**
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001179 * Set the estimated size of network traffic that will be performed by
1180 * this job, in bytes.
1181 * <p>
1182 * Apps are encouraged to provide values that are as accurate as
1183 * possible, but when the exact size isn't available, an
1184 * order-of-magnitude estimate can be provided instead. Here are some
1185 * specific examples:
1186 * <ul>
1187 * <li>A job that is backing up a photo knows the exact size of that
1188 * photo, so it should provide that size as the estimate.
1189 * <li>A job that refreshes top news stories wouldn't know an exact
1190 * size, but if the size is expected to be consistently around 100KB, it
1191 * can provide that order-of-magnitude value as the estimate.
1192 * <li>A job that synchronizes email could end up using an extreme range
1193 * of data, from under 1KB when nothing has changed, to dozens of MB
1194 * when there are new emails with attachments. Jobs that cannot provide
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001195 * reasonable estimates should use the sentinel value
1196 * {@link JobInfo#NETWORK_BYTES_UNKNOWN}.
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001197 * </ul>
1198 * Note that the system may choose to delay jobs with large network
1199 * usage estimates when the device has a poor network connection, in
1200 * order to save battery.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001201 * <p>
1202 * The values provided here only reflect the traffic that will be
1203 * performed by the base job; if you're using {@link JobWorkItem} then
1204 * you also need to define the network traffic used by each work item
1205 * when constructing them.
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001206 *
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001207 * @param downloadBytes The estimated size of network traffic that will
1208 * be downloaded by this job, in bytes.
1209 * @param uploadBytes The estimated size of network traffic that will be
1210 * uploaded by this job, in bytes.
1211 * @see JobInfo#getEstimatedNetworkDownloadBytes()
1212 * @see JobInfo#getEstimatedNetworkUploadBytes()
1213 * @see JobWorkItem#JobWorkItem(android.content.Intent, long, long)
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001214 */
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001215 public Builder setEstimatedNetworkBytes(@BytesLong long downloadBytes,
1216 @BytesLong long uploadBytes) {
1217 mNetworkDownloadBytes = downloadBytes;
1218 mNetworkUploadBytes = uploadBytes;
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001219 return this;
1220 }
1221
1222 /**
Christopher Tate78152512017-10-02 17:07:07 -07001223 * Specify that to run this job, the device must be charging (or be a
1224 * non-battery-powered device connected to permanent power, such as Android TV
1225 * devices). This defaults to {@code false}.
1226 *
1227 * <p class="note">For purposes of running jobs, a battery-powered device
1228 * "charging" is not quite the same as simply being connected to power. If the
1229 * device is so busy that the battery is draining despite a power connection, jobs
1230 * with this constraint will <em>not</em> run. This can happen during some
1231 * common use cases such as video chat, particularly if the device is plugged in
1232 * to USB rather than to wall power.
1233 *
1234 * @param requiresCharging Pass {@code true} to require that the device be
1235 * charging in order to run the job.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001236 * @see JobInfo#isRequireCharging()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001237 */
1238 public Builder setRequiresCharging(boolean requiresCharging) {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001239 mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_CHARGING)
1240 | (requiresCharging ? CONSTRAINT_FLAG_CHARGING : 0);
1241 return this;
1242 }
1243
1244 /**
1245 * Specify that to run this job, the device's battery level must not be low.
1246 * This defaults to false. If true, the job will only run when the battery level
1247 * is not low, which is generally the point where the user is given a "low battery"
1248 * warning.
1249 * @param batteryNotLow Whether or not the device's battery level must not be low.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001250 * @see JobInfo#isRequireBatteryNotLow()
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001251 */
1252 public Builder setRequiresBatteryNotLow(boolean batteryNotLow) {
1253 mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_BATTERY_NOT_LOW)
1254 | (batteryNotLow ? CONSTRAINT_FLAG_BATTERY_NOT_LOW : 0);
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001255 return this;
1256 }
1257
1258 /**
Christopher Tate78152512017-10-02 17:07:07 -07001259 * When set {@code true}, ensure that this job will not run if the device is in active use.
1260 * The default state is {@code false}: that is, the for the job to be runnable even when
1261 * someone is interacting with the device.
1262 *
1263 * <p>This state is a loose definition provided by the system. In general, it means that
1264 * the device is not currently being used interactively, and has not been in use for some
1265 * time. As such, it is a good time to perform resource heavy jobs. Bear in mind that
1266 * battery usage will still be attributed to your application, and surfaced to the user in
1267 * battery stats.</p>
1268 *
1269 * <p class="note">Despite the similar naming, this job constraint is <em>not</em>
1270 * related to the system's "device idle" or "doze" states. This constraint only
1271 * determines whether a job is allowed to run while the device is directly in use.
1272 *
1273 * @param requiresDeviceIdle Pass {@code true} to prevent the job from running
1274 * while the device is being used interactively.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001275 * @see JobInfo#isRequireDeviceIdle()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001276 */
1277 public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001278 mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_DEVICE_IDLE)
1279 | (requiresDeviceIdle ? CONSTRAINT_FLAG_DEVICE_IDLE : 0);
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001280 return this;
1281 }
1282
1283 /**
Dianne Hackborn532ea262017-03-17 17:50:55 -07001284 * Specify that to run this job, the device's available storage must not be low.
1285 * This defaults to false. If true, the job will only run when the device is not
1286 * in a low storage state, which is generally the point where the user is given a
1287 * "low storage" warning.
1288 * @param storageNotLow Whether or not the device's available storage must not be low.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001289 * @see JobInfo#isRequireStorageNotLow()
Dianne Hackborn532ea262017-03-17 17:50:55 -07001290 */
1291 public Builder setRequiresStorageNotLow(boolean storageNotLow) {
1292 mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_STORAGE_NOT_LOW)
1293 | (storageNotLow ? CONSTRAINT_FLAG_STORAGE_NOT_LOW : 0);
1294 return this;
1295 }
1296
1297 /**
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001298 * Add a new content: URI that will be monitored with a
1299 * {@link android.database.ContentObserver}, and will cause the job to execute if changed.
1300 * If you have any trigger content URIs associated with a job, it will not execute until
1301 * there has been a change report for one or more of them.
Dianne Hackborn532ea262017-03-17 17:50:55 -07001302 *
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001303 * <p>Note that trigger URIs can not be used in combination with
1304 * {@link #setPeriodic(long)} or {@link #setPersisted(boolean)}. To continually monitor
1305 * for content changes, you need to schedule a new JobInfo observing the same URIs
Dianne Hackborn532ea262017-03-17 17:50:55 -07001306 * before you finish execution of the JobService handling the most recent changes.
1307 * Following this pattern will ensure you do not lost any content changes: while your
1308 * job is running, the system will continue monitoring for content changes, and propagate
1309 * any it sees over to the next job you schedule.</p>
1310 *
1311 * <p>Because setting this property is not compatible with periodic or
Dianne Hackborn46499a52016-03-09 17:57:48 -08001312 * persisted jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
1313 * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
Dianne Hackbornc43a7f82016-06-01 10:48:43 -07001314 *
1315 * <p>The following example shows how this feature can be used to monitor for changes
1316 * in the photos on a device.</p>
1317 *
1318 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/PhotosContentJob.java
1319 * job}
1320 *
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001321 * @param uri The content: URI to monitor.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001322 * @see JobInfo#getTriggerContentUris()
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001323 */
1324 public Builder addTriggerContentUri(@NonNull TriggerContentUri uri) {
1325 if (mTriggerContentUris == null) {
1326 mTriggerContentUris = new ArrayList<>();
1327 }
1328 mTriggerContentUris.add(uri);
1329 return this;
1330 }
1331
1332 /**
Dianne Hackborn8db0fc12016-04-12 13:48:25 -07001333 * Set the delay (in milliseconds) from when a content change is detected until
1334 * the job is scheduled. If there are more changes during that time, the delay
1335 * will be reset to start at the time of the most recent change.
1336 * @param durationMs Delay after most recent content change, in milliseconds.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001337 * @see JobInfo#getTriggerContentUpdateDelay()
Dianne Hackborn8db0fc12016-04-12 13:48:25 -07001338 */
1339 public Builder setTriggerContentUpdateDelay(long durationMs) {
1340 mTriggerContentUpdateDelay = durationMs;
1341 return this;
1342 }
1343
1344 /**
1345 * Set the maximum total delay (in milliseconds) that is allowed from the first
1346 * time a content change is detected until the job is scheduled.
1347 * @param durationMs Delay after initial content change, in milliseconds.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001348 * @see JobInfo#getTriggerContentMaxDelay()
Dianne Hackborn8db0fc12016-04-12 13:48:25 -07001349 */
1350 public Builder setTriggerContentMaxDelay(long durationMs) {
1351 mTriggerContentMaxDelay = durationMs;
1352 return this;
1353 }
1354
1355 /**
Christopher Tate7060b042014-06-09 19:50:00 -07001356 * Specify that this job should recur with the provided interval, not more than once per
1357 * period. You have no control over when within this interval this job will be executed,
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001358 * only the guarantee that it will be executed at most once within this interval.
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001359 * Setting this function on the builder with {@link #setMinimumLatency(long)} or
1360 * {@link #setOverrideDeadline(long)} will result in an error.
Christopher Tate7060b042014-06-09 19:50:00 -07001361 * @param intervalMillis Millisecond interval for which this job will repeat.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001362 * @see JobInfo#getIntervalMillis()
1363 * @see JobInfo#getFlexMillis()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001364 */
1365 public Builder setPeriodic(long intervalMillis) {
Shreyas Basarge89ee6182015-12-17 15:16:36 +00001366 return setPeriodic(intervalMillis, intervalMillis);
1367 }
1368
1369 /**
1370 * Specify that this job should recur with the provided interval and flex. The job can
1371 * execute at any time in a window of flex length at the end of the period.
Shreyas Basargee96c3b72016-01-29 19:25:51 +00001372 * @param intervalMillis Millisecond interval for which this job will repeat. A minimum
Christopher Tatea9b4f3f2016-05-18 13:57:37 -07001373 * value of {@link #getMinPeriodMillis()} is enforced.
Shreyas Basarge89ee6182015-12-17 15:16:36 +00001374 * @param flexMillis Millisecond flex for this job. Flex is clamped to be at least
Christopher Tatea9b4f3f2016-05-18 13:57:37 -07001375 * {@link #getMinFlexMillis()} or 5 percent of the period, whichever is
Shreyas Basarge89ee6182015-12-17 15:16:36 +00001376 * higher.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001377 * @see JobInfo#getIntervalMillis()
1378 * @see JobInfo#getFlexMillis()
Shreyas Basarge89ee6182015-12-17 15:16:36 +00001379 */
1380 public Builder setPeriodic(long intervalMillis, long flexMillis) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001381 final long minPeriod = getMinPeriodMillis();
1382 if (intervalMillis < minPeriod) {
1383 Log.w(TAG, "Requested interval " + formatDuration(intervalMillis) + " for job "
1384 + mJobId + " is too small; raising to " + formatDuration(minPeriod));
1385 intervalMillis = minPeriod;
1386 }
1387
1388 final long percentClamp = 5 * intervalMillis / 100;
1389 final long minFlex = Math.max(percentClamp, getMinFlexMillis());
1390 if (flexMillis < minFlex) {
1391 Log.w(TAG, "Requested flex " + formatDuration(flexMillis) + " for job " + mJobId
1392 + " is too small; raising to " + formatDuration(minFlex));
1393 flexMillis = minFlex;
1394 }
1395
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001396 mIsPeriodic = true;
1397 mIntervalMillis = intervalMillis;
Shreyas Basarge89ee6182015-12-17 15:16:36 +00001398 mFlexMillis = flexMillis;
Matthew Williams9b9244b62014-05-14 11:06:04 -07001399 mHasEarlyConstraint = mHasLateConstraint = true;
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001400 return this;
1401 }
1402
1403 /**
Christopher Tate7060b042014-06-09 19:50:00 -07001404 * Specify that this job should be delayed by the provided amount of time.
1405 * Because it doesn't make sense setting this property on a periodic job, doing so will
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001406 * throw an {@link java.lang.IllegalArgumentException} when
Christopher Tate7060b042014-06-09 19:50:00 -07001407 * {@link android.app.job.JobInfo.Builder#build()} is called.
1408 * @param minLatencyMillis Milliseconds before which this job will not be considered for
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001409 * execution.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001410 * @see JobInfo#getMinLatencyMillis()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001411 */
1412 public Builder setMinimumLatency(long minLatencyMillis) {
1413 mMinLatencyMillis = minLatencyMillis;
Matthew Williams9b9244b62014-05-14 11:06:04 -07001414 mHasEarlyConstraint = true;
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001415 return this;
1416 }
1417
1418 /**
Christopher Tate7060b042014-06-09 19:50:00 -07001419 * Set deadline which is the maximum scheduling latency. The job will be run by this
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001420 * deadline even if other requirements are not met. Because it doesn't make sense setting
Christopher Tate7060b042014-06-09 19:50:00 -07001421 * this property on a periodic job, doing so will throw an
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001422 * {@link java.lang.IllegalArgumentException} when
Christopher Tate7060b042014-06-09 19:50:00 -07001423 * {@link android.app.job.JobInfo.Builder#build()} is called.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001424 * @see JobInfo#getMaxExecutionDelayMillis()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001425 */
1426 public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
1427 mMaxExecutionDelayMillis = maxExecutionDelayMillis;
Matthew Williams9b9244b62014-05-14 11:06:04 -07001428 mHasLateConstraint = true;
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001429 return this;
1430 }
1431
1432 /**
1433 * Set up the back-off/retry policy.
Matthew Williamsd1c06752014-08-22 14:15:28 -07001434 * This defaults to some respectable values: {30 seconds, Exponential}. We cap back-off at
1435 * 5hrs.
Christopher Tate7060b042014-06-09 19:50:00 -07001436 * Note that trying to set a backoff criteria for a job with
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001437 * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
Christopher Tate7060b042014-06-09 19:50:00 -07001438 * This is because back-off typically does not make sense for these types of jobs. See
1439 * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
1440 * for more description of the return value for the case of a job executing while in idle
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001441 * mode.
Christopher Tate7060b042014-06-09 19:50:00 -07001442 * @param initialBackoffMillis Millisecond time interval to wait initially when job has
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001443 * failed.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001444 * @see JobInfo#getInitialBackoffMillis()
1445 * @see JobInfo#getBackoffPolicy()
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001446 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -06001447 public Builder setBackoffCriteria(long initialBackoffMillis,
1448 @BackoffPolicy int backoffPolicy) {
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001449 final long minBackoff = getMinBackoffMillis();
1450 if (initialBackoffMillis < minBackoff) {
1451 Log.w(TAG, "Requested backoff " + formatDuration(initialBackoffMillis) + " for job "
1452 + mJobId + " is too small; raising to " + formatDuration(minBackoff));
1453 initialBackoffMillis = minBackoff;
1454 }
1455
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001456 mBackoffPolicySet = true;
1457 mInitialBackoffMillis = initialBackoffMillis;
1458 mBackoffPolicy = backoffPolicy;
1459 return this;
1460 }
1461
1462 /**
Suprabh Shukla106203b2017-11-02 21:23:44 -07001463 * Setting this to true indicates that this job is important while the scheduling app
1464 * is in the foreground or on the temporary whitelist for background restrictions.
1465 * This means that the system will relax doze restrictions on this job during this time.
1466 *
1467 * Apps should use this flag only for short jobs that are essential for the app to function
1468 * properly in the foreground.
1469 *
1470 * Note that once the scheduling app is no longer whitelisted from background restrictions
1471 * and in the background, or the job failed due to unsatisfied constraints,
1472 * this job should be expected to behave like other jobs without this flag.
1473 *
1474 * @param importantWhileForeground whether to relax doze restrictions for this job when the
1475 * app is in the foreground. False by default.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001476 * @see JobInfo#isImportantWhileForeground()
Suprabh Shukla106203b2017-11-02 21:23:44 -07001477 */
1478 public Builder setImportantWhileForeground(boolean importantWhileForeground) {
1479 if (importantWhileForeground) {
1480 mFlags |= FLAG_IMPORTANT_WHILE_FOREGROUND;
1481 } else {
1482 mFlags &= (~FLAG_IMPORTANT_WHILE_FOREGROUND);
1483 }
1484 return this;
1485 }
1486
1487 /**
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001488 * @removed
1489 * @deprecated replaced with {@link #setPrefetch(boolean)}
1490 */
1491 @Deprecated
1492 public Builder setIsPrefetch(boolean isPrefetch) {
1493 return setPrefetch(isPrefetch);
1494 }
1495
1496 /**
Jeff Sharkey9252b342018-01-19 07:58:35 +09001497 * Setting this to true indicates that this job is designed to prefetch
1498 * content that will make a material improvement to the experience of
1499 * the specific user of this device. For example, fetching top headlines
1500 * of interest to the current user.
1501 * <p>
1502 * The system may use this signal to relax the network constraints you
1503 * originally requested, such as allowing a
1504 * {@link JobInfo#NETWORK_TYPE_UNMETERED} job to run over a metered
1505 * network when there is a surplus of metered data available. The system
1506 * may also use this signal in combination with end user usage patterns
1507 * to ensure data is prefetched before the user launches your app.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001508 * @see JobInfo#isPrefetch()
Jeff Sharkey9252b342018-01-19 07:58:35 +09001509 */
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001510 public Builder setPrefetch(boolean prefetch) {
1511 if (prefetch) {
1512 mFlags |= FLAG_PREFETCH;
Jeff Sharkey9252b342018-01-19 07:58:35 +09001513 } else {
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001514 mFlags &= (~FLAG_PREFETCH);
Jeff Sharkey9252b342018-01-19 07:58:35 +09001515 }
1516 return this;
1517 }
1518
1519 /**
Jeff Sharkey30e06bb2017-04-24 11:18:03 -06001520 * Set whether or not to persist this job across device reboots.
1521 *
1522 * @param isPersisted True to indicate that the job will be written to
1523 * disk and loaded at boot.
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001524 * @see JobInfo#isPersisted()
Matthew Williams900c67f2014-07-09 12:46:53 -07001525 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -06001526 @RequiresPermission(android.Manifest.permission.RECEIVE_BOOT_COMPLETED)
Matthew Williamsd1c06752014-08-22 14:15:28 -07001527 public Builder setPersisted(boolean isPersisted) {
Matthew Williams900c67f2014-07-09 12:46:53 -07001528 mIsPersisted = isPersisted;
1529 return this;
1530 }
1531
1532 /**
Christopher Tate7060b042014-06-09 19:50:00 -07001533 * @return The job object to hand to the JobScheduler. This object is immutable.
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001534 */
Christopher Tate7060b042014-06-09 19:50:00 -07001535 public JobInfo build() {
Matthew Williams9ae3dbe2014-08-21 13:47:47 -07001536 // Allow jobs with no constraints - What am I, a database?
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001537 if (!mHasEarlyConstraint && !mHasLateConstraint && mConstraintFlags == 0 &&
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001538 mNetworkRequest == null &&
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001539 mTriggerContentUris == null) {
Matthew Williamsbafeeb92014-08-08 11:51:06 -07001540 throw new IllegalArgumentException("You're trying to build a job with no " +
1541 "constraints, this is not allowed.");
1542 }
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001543 // Check that network estimates require network type
Jeff Sharkey8474ca02018-03-26 19:10:02 -06001544 if ((mNetworkDownloadBytes > 0 || mNetworkUploadBytes > 0) && mNetworkRequest == null) {
Jeff Sharkeycaa3f8d2017-10-25 16:12:00 -06001545 throw new IllegalArgumentException(
1546 "Can't provide estimated network usage without requiring a network");
1547 }
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001548 // We can't serialize network specifiers
1549 if (mIsPersisted && mNetworkRequest != null
1550 && mNetworkRequest.networkCapabilities.getNetworkSpecifier() != null) {
1551 throw new IllegalArgumentException(
1552 "Network specifiers aren't supported for persistent jobs");
1553 }
Christopher Tate7060b042014-06-09 19:50:00 -07001554 // Check that a deadline was not set on a periodic job.
Dianne Hackborna47223f2017-03-30 13:49:13 -07001555 if (mIsPeriodic) {
1556 if (mMaxExecutionDelayMillis != 0L) {
1557 throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
1558 "periodic job.");
1559 }
1560 if (mMinLatencyMillis != 0L) {
1561 throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
1562 "periodic job");
1563 }
1564 if (mTriggerContentUris != null) {
1565 throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +
1566 "periodic job");
1567 }
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001568 }
Dianne Hackborna47223f2017-03-30 13:49:13 -07001569 if (mIsPersisted) {
1570 if (mTriggerContentUris != null) {
1571 throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +
1572 "persisted job");
1573 }
1574 if (!mTransientExtras.isEmpty()) {
1575 throw new IllegalArgumentException("Can't call setTransientExtras() on a " +
1576 "persisted job");
1577 }
1578 if (mClipData != null) {
1579 throw new IllegalArgumentException("Can't call setClipData() on a " +
1580 "persisted job");
1581 }
Dianne Hackbornba604732016-02-10 17:05:10 -08001582 }
Suprabh Shukla106203b2017-11-02 21:23:44 -07001583 if ((mFlags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0 && mHasEarlyConstraint) {
1584 throw new IllegalArgumentException("An important while foreground job cannot "
1585 + "have a time delay");
1586 }
Dianne Hackborna06ec6a2017-02-13 10:08:42 -08001587 if (mBackoffPolicySet && (mConstraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0) {
Christopher Tate7060b042014-06-09 19:50:00 -07001588 throw new IllegalArgumentException("An idle mode job will not respect any" +
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001589 " back-off policy, so calling setBackoffCriteria with" +
1590 " setRequiresDeviceIdle is an error.");
1591 }
Jeff Sharkeyd0fff2e2017-11-07 16:55:06 -07001592 return new JobInfo(this);
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001593 }
1594 }
Matthew Williams6e31c5c2014-04-11 15:49:16 -07001595}