• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.app.job;
18 
19 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
20 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
21 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
22 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
23 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
24 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
25 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
26 import static android.util.TimeUtils.formatDuration;
27 
28 import android.annotation.BytesLong;
29 import android.annotation.IntDef;
30 import android.annotation.NonNull;
31 import android.annotation.Nullable;
32 import android.annotation.RequiresPermission;
33 import android.compat.Compatibility;
34 import android.compat.annotation.ChangeId;
35 import android.compat.annotation.EnabledSince;
36 import android.compat.annotation.UnsupportedAppUsage;
37 import android.content.ClipData;
38 import android.content.ComponentName;
39 import android.net.NetworkRequest;
40 import android.net.NetworkSpecifier;
41 import android.net.Uri;
42 import android.os.BaseBundle;
43 import android.os.Build;
44 import android.os.Bundle;
45 import android.os.Parcel;
46 import android.os.Parcelable;
47 import android.os.PersistableBundle;
48 import android.util.Log;
49 
50 import java.lang.annotation.Retention;
51 import java.lang.annotation.RetentionPolicy;
52 import java.util.ArrayList;
53 import java.util.Arrays;
54 import java.util.Objects;
55 
56 /**
57  * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
58  * parameters required to schedule work against the calling application. These are constructed
59  * using the {@link JobInfo.Builder}.
60  * The goal here is to provide the scheduler with high-level semantics about the work you want to
61  * accomplish.
62  * <p> Prior to Android version {@link Build.VERSION_CODES#Q}, you had to specify at least one
63  * constraint on the JobInfo object that you are creating. Otherwise, the builder would throw an
64  * exception when building. From Android version {@link Build.VERSION_CODES#Q} and onwards, it is
65  * valid to schedule jobs with no constraints.
66  */
67 public class JobInfo implements Parcelable {
68     private static String TAG = "JobInfo";
69 
70     /**
71      * Disallow setting a deadline (via {@link Builder#setOverrideDeadline(long)}) for prefetch
72      * jobs ({@link Builder#setPrefetch(boolean)}. Prefetch jobs are meant to run close to the next
73      * app launch, so there's no good reason to allow them to have deadlines.
74      *
75      * We don't drop or cancel any previously scheduled prefetch jobs with a deadline.
76      * There's no way for an app to keep a perpetually scheduled prefetch job with a deadline.
77      * Prefetch jobs with a deadline will run and apps under this restriction won't be able to
78      * schedule new prefetch jobs with a deadline. If a job is rescheduled (by providing
79      * {@code true} via {@link JobService#jobFinished(JobParameters, boolean)} or
80      * {@link JobService#onStopJob(JobParameters)}'s return value),the deadline is dropped.
81      * Periodic jobs require all constraints to be met, so there's no issue with their deadlines.
82      *
83      * @hide
84      */
85     @ChangeId
86     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
87     public static final long DISALLOW_DEADLINES_FOR_PREFETCH_JOBS = 194532703L;
88 
89     /**
90      * Whether to throw an exception when an app provides an invalid priority value via
91      * {@link Builder#setPriority(int)}. Legacy apps may be incorrectly using the API and
92      * so the call will silently fail for them if they continue using the API.
93      *
94      * @hide
95      */
96     @ChangeId
97     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
98     public static final long THROW_ON_INVALID_PRIORITY_VALUE = 140852299L;
99 
100     /** @hide */
101     @IntDef(prefix = { "NETWORK_TYPE_" }, value = {
102             NETWORK_TYPE_NONE,
103             NETWORK_TYPE_ANY,
104             NETWORK_TYPE_UNMETERED,
105             NETWORK_TYPE_NOT_ROAMING,
106             NETWORK_TYPE_CELLULAR,
107     })
108     @Retention(RetentionPolicy.SOURCE)
109     public @interface NetworkType {}
110 
111     /** Default. */
112     public static final int NETWORK_TYPE_NONE = 0;
113     /** This job requires network connectivity. */
114     public static final int NETWORK_TYPE_ANY = 1;
115     /** This job requires network connectivity that is unmetered. */
116     public static final int NETWORK_TYPE_UNMETERED = 2;
117     /** This job requires network connectivity that is not roaming. */
118     public static final int NETWORK_TYPE_NOT_ROAMING = 3;
119     /** This job requires network connectivity that is a cellular network. */
120     public static final int NETWORK_TYPE_CELLULAR = 4;
121 
122     /**
123      * This job requires metered connectivity such as most cellular data
124      * networks.
125      *
126      * @deprecated Cellular networks may be unmetered, or Wi-Fi networks may be
127      *             metered, so this isn't a good way of selecting a specific
128      *             transport. Instead, use {@link #NETWORK_TYPE_CELLULAR} or
129      *             {@link android.net.NetworkRequest.Builder#addTransportType(int)}
130      *             if your job requires a specific network transport.
131      */
132     @Deprecated
133     public static final int NETWORK_TYPE_METERED = NETWORK_TYPE_CELLULAR;
134 
135     /** Sentinel value indicating that bytes are unknown. */
136     public static final int NETWORK_BYTES_UNKNOWN = -1;
137 
138     /**
139      * Amount of backoff a job has initially by default, in milliseconds.
140      */
141     public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L;  // 30 seconds.
142 
143     /**
144      * Maximum backoff we allow for a job, in milliseconds.
145      */
146     public static final long MAX_BACKOFF_DELAY_MILLIS = 5 * 60 * 60 * 1000;  // 5 hours.
147 
148     /** @hide */
149     @IntDef(prefix = { "BACKOFF_POLICY_" }, value = {
150             BACKOFF_POLICY_LINEAR,
151             BACKOFF_POLICY_EXPONENTIAL,
152     })
153     @Retention(RetentionPolicy.SOURCE)
154     public @interface BackoffPolicy {}
155 
156     /**
157      * Linearly back-off a failed job. See
158      * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}
159      * retry_time(current_time, num_failures) =
160      *     current_time + initial_backoff_millis * num_failures, num_failures >= 1
161      */
162     public static final int BACKOFF_POLICY_LINEAR = 0;
163 
164     /**
165      * Exponentially back-off a failed job. See
166      * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}
167      *
168      * retry_time(current_time, num_failures) =
169      *     current_time + initial_backoff_millis * 2 ^ (num_failures - 1), num_failures >= 1
170      */
171     public static final int BACKOFF_POLICY_EXPONENTIAL = 1;
172 
173     /* Minimum interval for a periodic job, in milliseconds. */
174     private static final long MIN_PERIOD_MILLIS = 15 * 60 * 1000L;   // 15 minutes
175 
176     /* Minimum flex for a periodic job, in milliseconds. */
177     private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
178 
179     /**
180      * Minimum backoff interval for a job, in milliseconds
181      * @hide
182      */
183     public static final long MIN_BACKOFF_MILLIS = 10 * 1000L;      // 10 seconds
184 
185     /**
186      * Query the minimum interval allowed for periodic scheduled jobs.  Attempting
187      * to declare a smaller period than this when scheduling a job will result in a
188      * job that is still periodic, but will run with this effective period.
189      *
190      * @return The minimum available interval for scheduling periodic jobs, in milliseconds.
191      */
getMinPeriodMillis()192     public static final long getMinPeriodMillis() {
193         return MIN_PERIOD_MILLIS;
194     }
195 
196     /**
197      * Query the minimum flex time allowed for periodic scheduled jobs.  Attempting
198      * to declare a shorter flex time than this when scheduling such a job will
199      * result in this amount as the effective flex time for the job.
200      *
201      * @return The minimum available flex time for scheduling periodic jobs, in milliseconds.
202      */
getMinFlexMillis()203     public static final long getMinFlexMillis() {
204         return MIN_FLEX_MILLIS;
205     }
206 
207     /**
208      * Query the minimum automatic-reschedule backoff interval permitted for jobs.
209      * @hide
210      */
getMinBackoffMillis()211     public static final long getMinBackoffMillis() {
212         return MIN_BACKOFF_MILLIS;
213     }
214 
215     /**
216      * Default type of backoff.
217      * @hide
218      */
219     public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL;
220 
221     /**
222      * Job has minimal value to the user. The user has absolutely no expectation
223      * or knowledge of this task and it has no bearing on the user's perception of
224      * the app whatsoever. JobScheduler <i>may</i> decide to defer these tasks while
225      * there are higher priority tasks in order to ensure there is sufficient quota
226      * available for the higher priority tasks.
227      * A sample task of min priority: uploading analytics
228      */
229     public static final int PRIORITY_MIN = 100;
230 
231     /**
232      * Low priority. The task provides some benefit to users, but is not critical
233      * and is more of a nice-to-have. This is more important than minimum priority
234      * jobs and will be prioritized ahead of them, but may still be deferred in lieu
235      * of higher priority jobs. JobScheduler <i>may</i> decide to defer these tasks
236      * while there are higher priority tasks in order to ensure there is sufficient
237      * quota available for the higher priority tasks.
238      * A sample task of low priority: prefetching data the user hasn't requested
239      */
240     public static final int PRIORITY_LOW = 200;
241 
242     /**
243      * Default value for all regular jobs. As noted in {@link JobScheduler},
244      * these jobs have a general execution time of 10 minutes.
245      * Receives the standard job management policy.
246      */
247     public static final int PRIORITY_DEFAULT = 300;
248 
249     /**
250      * This task should be ordered ahead of most other tasks. It may be
251      * deferred a little, but if it doesn't run at some point, the user may think
252      * something is wrong. Assuming all constraints remain satisfied
253      * (including ideal system load conditions), these jobs can have an
254      * execution time of at least 4 minutes. Setting all of your jobs to high
255      * priority will not be beneficial to your app and in fact may hurt its
256      * performance in the long run.
257      */
258     public static final int PRIORITY_HIGH = 400;
259 
260     /**
261      * This task should be run ahead of all other tasks. Only Expedited Jobs
262      * {@link Builder#setExpedited(boolean)} can have this priority and as such,
263      * are subject to the same execution time details noted in
264      * {@link Builder#setExpedited(boolean)}.
265      * A sample task of max priority: receiving a text message and processing it to
266      * show a notification
267      */
268     public static final int PRIORITY_MAX = 500;
269 
270     /** @hide */
271     @IntDef(prefix = {"PRIORITY_"}, value = {
272             PRIORITY_MIN,
273             PRIORITY_LOW,
274             PRIORITY_DEFAULT,
275             PRIORITY_HIGH,
276             PRIORITY_MAX,
277     })
278     @Retention(RetentionPolicy.SOURCE)
279     public @interface Priority {
280     }
281 
282     /**
283      * Default of {@link #getBias}.
284      * @hide
285      */
286     public static final int BIAS_DEFAULT = 0;
287 
288     /**
289      * Value of {@link #getBias} for expedited syncs.
290      * @hide
291      */
292     public static final int BIAS_SYNC_EXPEDITED = 10;
293 
294     /**
295      * Value of {@link #getBias} for first time initialization syncs.
296      * @hide
297      */
298     public static final int BIAS_SYNC_INITIALIZATION = 20;
299 
300     /**
301      * Value of {@link #getBias} for a BFGS app (overrides the supplied
302      * JobInfo bias if it is smaller).
303      * @hide
304      */
305     public static final int BIAS_BOUND_FOREGROUND_SERVICE = 30;
306 
307     /** @hide For backward compatibility. */
308     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
309     public static final int PRIORITY_FOREGROUND_APP = BIAS_BOUND_FOREGROUND_SERVICE;
310 
311     /**
312      * Value of {@link #getBias} for a FG service app (overrides the supplied
313      * JobInfo bias if it is smaller).
314      * @hide
315      */
316     public static final int BIAS_FOREGROUND_SERVICE = 35;
317 
318     /** @hide For backward compatibility. */
319     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
320     public static final int PRIORITY_FOREGROUND_SERVICE = BIAS_FOREGROUND_SERVICE;
321 
322     /**
323      * Value of {@link #getBias} for the current top app (overrides the supplied
324      * JobInfo bias if it is smaller).
325      * @hide
326      */
327     public static final int BIAS_TOP_APP = 40;
328 
329     /**
330      * Adjustment of {@link #getBias} if the app has often (50% or more of the time)
331      * been running jobs.
332      * @hide
333      */
334     public static final int BIAS_ADJ_OFTEN_RUNNING = -40;
335 
336     /**
337      * Adjustment of {@link #getBias} if the app has always (90% or more of the time)
338      * been running jobs.
339      * @hide
340      */
341     public static final int BIAS_ADJ_ALWAYS_RUNNING = -80;
342 
343     /**
344      * Indicates that the implementation of this job will be using
345      * {@link JobService#startForeground(int, android.app.Notification)} to run
346      * in the foreground.
347      * <p>
348      * When set, the internal scheduling of this job will ignore any background
349      * network restrictions for the requesting app. Note that this flag alone
350      * doesn't actually place your {@link JobService} in the foreground; you
351      * still need to post the notification yourself.
352      * <p>
353      * To use this flag, the caller must hold the
354      * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL} permission.
355      *
356      * @hide
357      */
358     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
359     public static final int FLAG_WILL_BE_FOREGROUND = 1 << 0;
360 
361     /**
362      * Allows this job to run despite doze restrictions as long as the app is in the foreground
363      * or on the temporary whitelist
364      * @hide
365      */
366     public static final int FLAG_IMPORTANT_WHILE_FOREGROUND = 1 << 1;
367 
368     /**
369      * @hide
370      */
371     public static final int FLAG_PREFETCH = 1 << 2;
372 
373     /**
374      * This job needs to be exempted from the app standby throttling. Only the system (UID 1000)
375      * can set it. Jobs with a time constraint must not have it.
376      *
377      * @hide
378      */
379     public static final int FLAG_EXEMPT_FROM_APP_STANDBY = 1 << 3;
380 
381     /**
382      * Whether it's an expedited job or not.
383      *
384      * @hide
385      */
386     public static final int FLAG_EXPEDITED = 1 << 4;
387 
388     /**
389      * @hide
390      */
391     public static final int CONSTRAINT_FLAG_CHARGING = 1 << 0;
392 
393     /**
394      * @hide
395      */
396     public static final int CONSTRAINT_FLAG_BATTERY_NOT_LOW = 1 << 1;
397 
398     /**
399      * @hide
400      */
401     public static final int CONSTRAINT_FLAG_DEVICE_IDLE = 1 << 2;
402 
403     /**
404      * @hide
405      */
406     public static final int CONSTRAINT_FLAG_STORAGE_NOT_LOW = 1 << 3;
407 
408     @UnsupportedAppUsage
409     private final int jobId;
410     private final PersistableBundle extras;
411     private final Bundle transientExtras;
412     private final ClipData clipData;
413     private final int clipGrantFlags;
414     @UnsupportedAppUsage
415     private final ComponentName service;
416     private final int constraintFlags;
417     private final TriggerContentUri[] triggerContentUris;
418     private final long triggerContentUpdateDelay;
419     private final long triggerContentMaxDelay;
420     private final boolean hasEarlyConstraint;
421     private final boolean hasLateConstraint;
422     private final NetworkRequest networkRequest;
423     private final long networkDownloadBytes;
424     private final long networkUploadBytes;
425     private final long minimumNetworkChunkBytes;
426     private final long minLatencyMillis;
427     private final long maxExecutionDelayMillis;
428     private final boolean isPeriodic;
429     private final boolean isPersisted;
430     private final long intervalMillis;
431     private final long flexMillis;
432     private final long initialBackoffMillis;
433     private final int backoffPolicy;
434     private final int mBias;
435     @Priority
436     private final int mPriority;
437     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
438     private final int flags;
439 
440     /**
441      * Unique job id associated with this application (uid).  This is the same job ID
442      * you supplied in the {@link Builder} constructor.
443      */
getId()444     public int getId() {
445         return jobId;
446     }
447 
448     /**
449      * @see JobInfo.Builder#setExtras(PersistableBundle)
450      */
getExtras()451     public @NonNull PersistableBundle getExtras() {
452         return extras;
453     }
454 
455     /**
456      * @see JobInfo.Builder#setTransientExtras(Bundle)
457      */
getTransientExtras()458     public @NonNull Bundle getTransientExtras() {
459         return transientExtras;
460     }
461 
462     /**
463      * @see JobInfo.Builder#setClipData(ClipData, int)
464      */
getClipData()465     public @Nullable ClipData getClipData() {
466         return clipData;
467     }
468 
469     /**
470      * @see JobInfo.Builder#setClipData(ClipData, int)
471      */
getClipGrantFlags()472     public int getClipGrantFlags() {
473         return clipGrantFlags;
474     }
475 
476     /**
477      * Name of the service endpoint that will be called back into by the JobScheduler.
478      */
getService()479     public @NonNull ComponentName getService() {
480         return service;
481     }
482 
483     /** @hide */
getBias()484     public int getBias() {
485         return mBias;
486     }
487 
488     /**
489      * @see JobInfo.Builder#setPriority(int)
490      */
491     @Priority
getPriority()492     public int getPriority() {
493         return mPriority;
494     }
495 
496     /** @hide */
getFlags()497     public int getFlags() {
498         return flags;
499     }
500 
501     /** @hide */
isExemptedFromAppStandby()502     public boolean isExemptedFromAppStandby() {
503         return ((flags & FLAG_EXEMPT_FROM_APP_STANDBY) != 0) && !isPeriodic();
504     }
505 
506     /**
507      * @see JobInfo.Builder#setRequiresCharging(boolean)
508      */
isRequireCharging()509     public boolean isRequireCharging() {
510         return (constraintFlags & CONSTRAINT_FLAG_CHARGING) != 0;
511     }
512 
513     /**
514      * @see JobInfo.Builder#setRequiresBatteryNotLow(boolean)
515      */
isRequireBatteryNotLow()516     public boolean isRequireBatteryNotLow() {
517         return (constraintFlags & CONSTRAINT_FLAG_BATTERY_NOT_LOW) != 0;
518     }
519 
520     /**
521      * @see JobInfo.Builder#setRequiresDeviceIdle(boolean)
522      */
isRequireDeviceIdle()523     public boolean isRequireDeviceIdle() {
524         return (constraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0;
525     }
526 
527     /**
528      * @see JobInfo.Builder#setRequiresStorageNotLow(boolean)
529      */
isRequireStorageNotLow()530     public boolean isRequireStorageNotLow() {
531         return (constraintFlags & CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0;
532     }
533 
534     /**
535      * @hide
536      */
getConstraintFlags()537     public int getConstraintFlags() {
538         return constraintFlags;
539     }
540 
541     /**
542      * Which content: URIs must change for the job to be scheduled.  Returns null
543      * if there are none required.
544      * @see JobInfo.Builder#addTriggerContentUri(TriggerContentUri)
545      */
getTriggerContentUris()546     public @Nullable TriggerContentUri[] getTriggerContentUris() {
547         return triggerContentUris;
548     }
549 
550     /**
551      * When triggering on content URI changes, this is the delay from when a change
552      * is detected until the job is scheduled.
553      * @see JobInfo.Builder#setTriggerContentUpdateDelay(long)
554      */
getTriggerContentUpdateDelay()555     public long getTriggerContentUpdateDelay() {
556         return triggerContentUpdateDelay;
557     }
558 
559     /**
560      * When triggering on content URI changes, this is the maximum delay we will
561      * use before scheduling the job.
562      * @see JobInfo.Builder#setTriggerContentMaxDelay(long)
563      */
getTriggerContentMaxDelay()564     public long getTriggerContentMaxDelay() {
565         return triggerContentMaxDelay;
566     }
567 
568     /**
569      * Return the basic description of the kind of network this job requires.
570      *
571      * @deprecated This method attempts to map {@link #getRequiredNetwork()}
572      *             into the set of simple constants, which results in a loss of
573      *             fidelity. Callers should move to using
574      *             {@link #getRequiredNetwork()} directly.
575      * @see Builder#setRequiredNetworkType(int)
576      */
577     @Deprecated
getNetworkType()578     public @NetworkType int getNetworkType() {
579         if (networkRequest == null) {
580             return NETWORK_TYPE_NONE;
581         } else if (networkRequest.hasCapability(NET_CAPABILITY_NOT_METERED)) {
582             return NETWORK_TYPE_UNMETERED;
583         } else if (networkRequest.hasCapability(NET_CAPABILITY_NOT_ROAMING)) {
584             return NETWORK_TYPE_NOT_ROAMING;
585         } else if (networkRequest.hasTransport(TRANSPORT_CELLULAR)) {
586             return NETWORK_TYPE_CELLULAR;
587         } else {
588             return NETWORK_TYPE_ANY;
589         }
590     }
591 
592     /**
593      * Return the detailed description of the kind of network this job requires,
594      * or {@code null} if no specific kind of network is required.
595      *
596      * @see Builder#setRequiredNetwork(NetworkRequest)
597      */
getRequiredNetwork()598     public @Nullable NetworkRequest getRequiredNetwork() {
599         return networkRequest;
600     }
601 
602     /**
603      * Return the estimated size of download traffic that will be performed by
604      * this job, in bytes.
605      *
606      * @return Estimated size of download traffic, or
607      *         {@link #NETWORK_BYTES_UNKNOWN} when unknown.
608      * @see Builder#setEstimatedNetworkBytes(long, long)
609      */
getEstimatedNetworkDownloadBytes()610     public @BytesLong long getEstimatedNetworkDownloadBytes() {
611         return networkDownloadBytes;
612     }
613 
614     /**
615      * Return the estimated size of upload traffic that will be performed by
616      * this job, in bytes.
617      *
618      * @return Estimated size of upload traffic, or
619      *         {@link #NETWORK_BYTES_UNKNOWN} when unknown.
620      * @see Builder#setEstimatedNetworkBytes(long, long)
621      */
getEstimatedNetworkUploadBytes()622     public @BytesLong long getEstimatedNetworkUploadBytes() {
623         return networkUploadBytes;
624     }
625 
626     /**
627      * Return the smallest piece of data that cannot be easily paused and resumed, in bytes.
628      *
629      * @return Smallest piece of data that cannot be easily paused and resumed, or
630      *         {@link #NETWORK_BYTES_UNKNOWN} when unknown.
631      * @see Builder#setMinimumNetworkChunkBytes(long)
632      */
getMinimumNetworkChunkBytes()633     public @BytesLong long getMinimumNetworkChunkBytes() {
634         return minimumNetworkChunkBytes;
635     }
636 
637     /**
638      * Set for a job that does not recur periodically, to specify a delay after which the job
639      * will be eligible for execution. This value is not set if the job recurs periodically.
640      * @see JobInfo.Builder#setMinimumLatency(long)
641      */
getMinLatencyMillis()642     public long getMinLatencyMillis() {
643         return minLatencyMillis;
644     }
645 
646     /**
647      * @see JobInfo.Builder#setOverrideDeadline(long)
648      */
getMaxExecutionDelayMillis()649     public long getMaxExecutionDelayMillis() {
650         return maxExecutionDelayMillis;
651     }
652 
653     /**
654      * Track whether this job will repeat with a given period.
655      * @see JobInfo.Builder#setPeriodic(long)
656      * @see JobInfo.Builder#setPeriodic(long, long)
657      */
isPeriodic()658     public boolean isPeriodic() {
659         return isPeriodic;
660     }
661 
662     /**
663      * @see JobInfo.Builder#setPersisted(boolean)
664      */
isPersisted()665     public boolean isPersisted() {
666         return isPersisted;
667     }
668 
669     /**
670      * Set to the interval between occurrences of this job. This value is <b>not</b> set if the
671      * job does not recur periodically.
672      * @see JobInfo.Builder#setPeriodic(long)
673      * @see JobInfo.Builder#setPeriodic(long, long)
674      */
getIntervalMillis()675     public long getIntervalMillis() {
676         return intervalMillis;
677     }
678 
679     /**
680      * Flex time for this job. Only valid if this is a periodic job.  The job can
681      * execute at any time in a window of flex length at the end of the period.
682      * @see JobInfo.Builder#setPeriodic(long)
683      * @see JobInfo.Builder#setPeriodic(long, long)
684      */
getFlexMillis()685     public long getFlexMillis() {
686         return flexMillis;
687     }
688 
689     /**
690      * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
691      * will be increased depending on the backoff policy specified at job creation time. Defaults
692      * to 30 seconds, minimum is currently 10 seconds.
693      * @see JobInfo.Builder#setBackoffCriteria(long, int)
694      */
getInitialBackoffMillis()695     public long getInitialBackoffMillis() {
696         return initialBackoffMillis;
697     }
698 
699     /**
700      * Return the backoff policy of this job.
701      *
702      * @see JobInfo.Builder#setBackoffCriteria(long, int)
703      */
getBackoffPolicy()704     public @BackoffPolicy int getBackoffPolicy() {
705         return backoffPolicy;
706     }
707 
708     /**
709      * @see JobInfo.Builder#setExpedited(boolean)
710      */
isExpedited()711     public boolean isExpedited() {
712         return (flags & FLAG_EXPEDITED) != 0;
713     }
714 
715     /**
716      * @see JobInfo.Builder#setImportantWhileForeground(boolean)
717      */
isImportantWhileForeground()718     public boolean isImportantWhileForeground() {
719         return (flags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0;
720     }
721 
722     /**
723      * @see JobInfo.Builder#setPrefetch(boolean)
724      */
isPrefetch()725     public boolean isPrefetch() {
726         return (flags & FLAG_PREFETCH) != 0;
727     }
728 
729     /**
730      * User can specify an early constraint of 0L, which is valid, so we keep track of whether the
731      * function was called at all.
732      * @hide
733      */
hasEarlyConstraint()734     public boolean hasEarlyConstraint() {
735         return hasEarlyConstraint;
736     }
737 
738     /**
739      * User can specify a late constraint of 0L, which is valid, so we keep track of whether the
740      * function was called at all.
741      * @hide
742      */
hasLateConstraint()743     public boolean hasLateConstraint() {
744         return hasLateConstraint;
745     }
746 
747     @Override
equals(Object o)748     public boolean equals(Object o) {
749         if (!(o instanceof JobInfo)) {
750             return false;
751         }
752         JobInfo j = (JobInfo) o;
753         if (jobId != j.jobId) {
754             return false;
755         }
756         // XXX won't be correct if one is parcelled and the other not.
757         if (!BaseBundle.kindofEquals(extras, j.extras)) {
758             return false;
759         }
760         // XXX won't be correct if one is parcelled and the other not.
761         if (!BaseBundle.kindofEquals(transientExtras, j.transientExtras)) {
762             return false;
763         }
764         // XXX for now we consider two different clip data objects to be different,
765         // regardless of whether their contents are the same.
766         if (clipData != j.clipData) {
767             return false;
768         }
769         if (clipGrantFlags != j.clipGrantFlags) {
770             return false;
771         }
772         if (!Objects.equals(service, j.service)) {
773             return false;
774         }
775         if (constraintFlags != j.constraintFlags) {
776             return false;
777         }
778         if (!Arrays.equals(triggerContentUris, j.triggerContentUris)) {
779             return false;
780         }
781         if (triggerContentUpdateDelay != j.triggerContentUpdateDelay) {
782             return false;
783         }
784         if (triggerContentMaxDelay != j.triggerContentMaxDelay) {
785             return false;
786         }
787         if (hasEarlyConstraint != j.hasEarlyConstraint) {
788             return false;
789         }
790         if (hasLateConstraint != j.hasLateConstraint) {
791             return false;
792         }
793         if (!Objects.equals(networkRequest, j.networkRequest)) {
794             return false;
795         }
796         if (networkDownloadBytes != j.networkDownloadBytes) {
797             return false;
798         }
799         if (networkUploadBytes != j.networkUploadBytes) {
800             return false;
801         }
802         if (minimumNetworkChunkBytes != j.minimumNetworkChunkBytes) {
803             return false;
804         }
805         if (minLatencyMillis != j.minLatencyMillis) {
806             return false;
807         }
808         if (maxExecutionDelayMillis != j.maxExecutionDelayMillis) {
809             return false;
810         }
811         if (isPeriodic != j.isPeriodic) {
812             return false;
813         }
814         if (isPersisted != j.isPersisted) {
815             return false;
816         }
817         if (intervalMillis != j.intervalMillis) {
818             return false;
819         }
820         if (flexMillis != j.flexMillis) {
821             return false;
822         }
823         if (initialBackoffMillis != j.initialBackoffMillis) {
824             return false;
825         }
826         if (backoffPolicy != j.backoffPolicy) {
827             return false;
828         }
829         if (mBias != j.mBias) {
830             return false;
831         }
832         if (mPriority != j.mPriority) {
833             return false;
834         }
835         if (flags != j.flags) {
836             return false;
837         }
838         return true;
839     }
840 
841     @Override
hashCode()842     public int hashCode() {
843         int hashCode = jobId;
844         if (extras != null) {
845             hashCode = 31 * hashCode + extras.hashCode();
846         }
847         if (transientExtras != null) {
848             hashCode = 31 * hashCode + transientExtras.hashCode();
849         }
850         if (clipData != null) {
851             hashCode = 31 * hashCode + clipData.hashCode();
852         }
853         hashCode = 31*hashCode + clipGrantFlags;
854         if (service != null) {
855             hashCode = 31 * hashCode + service.hashCode();
856         }
857         hashCode = 31 * hashCode + constraintFlags;
858         if (triggerContentUris != null) {
859             hashCode = 31 * hashCode + Arrays.hashCode(triggerContentUris);
860         }
861         hashCode = 31 * hashCode + Long.hashCode(triggerContentUpdateDelay);
862         hashCode = 31 * hashCode + Long.hashCode(triggerContentMaxDelay);
863         hashCode = 31 * hashCode + Boolean.hashCode(hasEarlyConstraint);
864         hashCode = 31 * hashCode + Boolean.hashCode(hasLateConstraint);
865         if (networkRequest != null) {
866             hashCode = 31 * hashCode + networkRequest.hashCode();
867         }
868         hashCode = 31 * hashCode + Long.hashCode(networkDownloadBytes);
869         hashCode = 31 * hashCode + Long.hashCode(networkUploadBytes);
870         hashCode = 31 * hashCode + Long.hashCode(minimumNetworkChunkBytes);
871         hashCode = 31 * hashCode + Long.hashCode(minLatencyMillis);
872         hashCode = 31 * hashCode + Long.hashCode(maxExecutionDelayMillis);
873         hashCode = 31 * hashCode + Boolean.hashCode(isPeriodic);
874         hashCode = 31 * hashCode + Boolean.hashCode(isPersisted);
875         hashCode = 31 * hashCode + Long.hashCode(intervalMillis);
876         hashCode = 31 * hashCode + Long.hashCode(flexMillis);
877         hashCode = 31 * hashCode + Long.hashCode(initialBackoffMillis);
878         hashCode = 31 * hashCode + backoffPolicy;
879         hashCode = 31 * hashCode + mBias;
880         hashCode = 31 * hashCode + mPriority;
881         hashCode = 31 * hashCode + flags;
882         return hashCode;
883     }
884 
885     @SuppressWarnings("UnsafeParcelApi")
JobInfo(Parcel in)886     private JobInfo(Parcel in) {
887         jobId = in.readInt();
888         extras = in.readPersistableBundle();
889         transientExtras = in.readBundle();
890         if (in.readInt() != 0) {
891             clipData = ClipData.CREATOR.createFromParcel(in);
892             clipGrantFlags = in.readInt();
893         } else {
894             clipData = null;
895             clipGrantFlags = 0;
896         }
897         service = in.readParcelable(null);
898         constraintFlags = in.readInt();
899         triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR);
900         triggerContentUpdateDelay = in.readLong();
901         triggerContentMaxDelay = in.readLong();
902         if (in.readInt() != 0) {
903             networkRequest = NetworkRequest.CREATOR.createFromParcel(in);
904         } else {
905             networkRequest = null;
906         }
907         networkDownloadBytes = in.readLong();
908         networkUploadBytes = in.readLong();
909         minimumNetworkChunkBytes = in.readLong();
910         minLatencyMillis = in.readLong();
911         maxExecutionDelayMillis = in.readLong();
912         isPeriodic = in.readInt() == 1;
913         isPersisted = in.readInt() == 1;
914         intervalMillis = in.readLong();
915         flexMillis = in.readLong();
916         initialBackoffMillis = in.readLong();
917         backoffPolicy = in.readInt();
918         hasEarlyConstraint = in.readInt() == 1;
919         hasLateConstraint = in.readInt() == 1;
920         mBias = in.readInt();
921         mPriority = in.readInt();
922         flags = in.readInt();
923     }
924 
JobInfo(JobInfo.Builder b)925     private JobInfo(JobInfo.Builder b) {
926         jobId = b.mJobId;
927         extras = b.mExtras.deepCopy();
928         transientExtras = b.mTransientExtras.deepCopy();
929         clipData = b.mClipData;
930         clipGrantFlags = b.mClipGrantFlags;
931         service = b.mJobService;
932         constraintFlags = b.mConstraintFlags;
933         triggerContentUris = b.mTriggerContentUris != null
934                 ? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()])
935                 : null;
936         triggerContentUpdateDelay = b.mTriggerContentUpdateDelay;
937         triggerContentMaxDelay = b.mTriggerContentMaxDelay;
938         networkRequest = b.mNetworkRequest;
939         networkDownloadBytes = b.mNetworkDownloadBytes;
940         networkUploadBytes = b.mNetworkUploadBytes;
941         minimumNetworkChunkBytes = b.mMinimumNetworkChunkBytes;
942         minLatencyMillis = b.mMinLatencyMillis;
943         maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
944         isPeriodic = b.mIsPeriodic;
945         isPersisted = b.mIsPersisted;
946         intervalMillis = b.mIntervalMillis;
947         flexMillis = b.mFlexMillis;
948         initialBackoffMillis = b.mInitialBackoffMillis;
949         backoffPolicy = b.mBackoffPolicy;
950         hasEarlyConstraint = b.mHasEarlyConstraint;
951         hasLateConstraint = b.mHasLateConstraint;
952         mBias = b.mBias;
953         mPriority = b.mPriority;
954         flags = b.mFlags;
955     }
956 
957     @Override
describeContents()958     public int describeContents() {
959         return 0;
960     }
961 
962     @Override
writeToParcel(Parcel out, int flags)963     public void writeToParcel(Parcel out, int flags) {
964         out.writeInt(jobId);
965         out.writePersistableBundle(extras);
966         out.writeBundle(transientExtras);
967         if (clipData != null) {
968             out.writeInt(1);
969             clipData.writeToParcel(out, flags);
970             out.writeInt(clipGrantFlags);
971         } else {
972             out.writeInt(0);
973         }
974         out.writeParcelable(service, flags);
975         out.writeInt(constraintFlags);
976         out.writeTypedArray(triggerContentUris, flags);
977         out.writeLong(triggerContentUpdateDelay);
978         out.writeLong(triggerContentMaxDelay);
979         if (networkRequest != null) {
980             out.writeInt(1);
981             networkRequest.writeToParcel(out, flags);
982         } else {
983             out.writeInt(0);
984         }
985         out.writeLong(networkDownloadBytes);
986         out.writeLong(networkUploadBytes);
987         out.writeLong(minimumNetworkChunkBytes);
988         out.writeLong(minLatencyMillis);
989         out.writeLong(maxExecutionDelayMillis);
990         out.writeInt(isPeriodic ? 1 : 0);
991         out.writeInt(isPersisted ? 1 : 0);
992         out.writeLong(intervalMillis);
993         out.writeLong(flexMillis);
994         out.writeLong(initialBackoffMillis);
995         out.writeInt(backoffPolicy);
996         out.writeInt(hasEarlyConstraint ? 1 : 0);
997         out.writeInt(hasLateConstraint ? 1 : 0);
998         out.writeInt(mBias);
999         out.writeInt(mPriority);
1000         out.writeInt(this.flags);
1001     }
1002 
1003     public static final @android.annotation.NonNull Creator<JobInfo> CREATOR = new Creator<JobInfo>() {
1004         @Override
1005         public JobInfo createFromParcel(Parcel in) {
1006             return new JobInfo(in);
1007         }
1008 
1009         @Override
1010         public JobInfo[] newArray(int size) {
1011             return new JobInfo[size];
1012         }
1013     };
1014 
1015     @Override
toString()1016     public String toString() {
1017         return "(job:" + jobId + "/" + service.flattenToShortString() + ")";
1018     }
1019 
1020     /**
1021      * Information about a content URI modification that a job would like to
1022      * trigger on.
1023      */
1024     public static final class TriggerContentUri implements Parcelable {
1025         private final Uri mUri;
1026         private final int mFlags;
1027 
1028         /** @hide */
1029         @Retention(RetentionPolicy.SOURCE)
1030         @IntDef(flag = true, prefix = { "FLAG_" }, value = {
1031                 FLAG_NOTIFY_FOR_DESCENDANTS,
1032         })
1033         public @interface Flags { }
1034 
1035         /**
1036          * Flag for trigger: also trigger if any descendants of the given URI change.
1037          * Corresponds to the <var>notifyForDescendants</var> of
1038          * {@link android.content.ContentResolver#registerContentObserver}.
1039          */
1040         public static final int FLAG_NOTIFY_FOR_DESCENDANTS = 1<<0;
1041 
1042         /**
1043          * Create a new trigger description.
1044          * @param uri The URI to observe.  Must be non-null.
1045          * @param flags Flags for the observer.
1046          */
TriggerContentUri(@onNull Uri uri, @Flags int flags)1047         public TriggerContentUri(@NonNull Uri uri, @Flags int flags) {
1048             mUri = Objects.requireNonNull(uri);
1049             mFlags = flags;
1050         }
1051 
1052         /**
1053          * Return the Uri this trigger was created for.
1054          */
getUri()1055         public Uri getUri() {
1056             return mUri;
1057         }
1058 
1059         /**
1060          * Return the flags supplied for the trigger.
1061          */
getFlags()1062         public @Flags int getFlags() {
1063             return mFlags;
1064         }
1065 
1066         @Override
equals(Object o)1067         public boolean equals(Object o) {
1068             if (!(o instanceof TriggerContentUri)) {
1069                 return false;
1070             }
1071             TriggerContentUri t = (TriggerContentUri) o;
1072             return Objects.equals(t.mUri, mUri) && t.mFlags == mFlags;
1073         }
1074 
1075         @Override
hashCode()1076         public int hashCode() {
1077             return (mUri == null ? 0 : mUri.hashCode()) ^ mFlags;
1078         }
1079 
TriggerContentUri(Parcel in)1080         private TriggerContentUri(Parcel in) {
1081             mUri = Uri.CREATOR.createFromParcel(in);
1082             mFlags = in.readInt();
1083         }
1084 
1085         @Override
describeContents()1086         public int describeContents() {
1087             return 0;
1088         }
1089 
1090         @Override
writeToParcel(Parcel out, int flags)1091         public void writeToParcel(Parcel out, int flags) {
1092             mUri.writeToParcel(out, flags);
1093             out.writeInt(mFlags);
1094         }
1095 
1096         public static final @android.annotation.NonNull Creator<TriggerContentUri> CREATOR = new Creator<TriggerContentUri>() {
1097             @Override
1098             public TriggerContentUri createFromParcel(Parcel in) {
1099                 return new TriggerContentUri(in);
1100             }
1101 
1102             @Override
1103             public TriggerContentUri[] newArray(int size) {
1104                 return new TriggerContentUri[size];
1105             }
1106         };
1107     }
1108 
1109     /** Builder class for constructing {@link JobInfo} objects. */
1110     public static final class Builder {
1111         private final int mJobId;
1112         private final ComponentName mJobService;
1113         private PersistableBundle mExtras = PersistableBundle.EMPTY;
1114         private Bundle mTransientExtras = Bundle.EMPTY;
1115         private ClipData mClipData;
1116         private int mClipGrantFlags;
1117         private int mBias = BIAS_DEFAULT;
1118         @Priority
1119         private int mPriority = PRIORITY_DEFAULT;
1120         private int mFlags;
1121         // Requirements.
1122         private int mConstraintFlags;
1123         private NetworkRequest mNetworkRequest;
1124         private long mNetworkDownloadBytes = NETWORK_BYTES_UNKNOWN;
1125         private long mNetworkUploadBytes = NETWORK_BYTES_UNKNOWN;
1126         private long mMinimumNetworkChunkBytes = NETWORK_BYTES_UNKNOWN;
1127         private ArrayList<TriggerContentUri> mTriggerContentUris;
1128         private long mTriggerContentUpdateDelay = -1;
1129         private long mTriggerContentMaxDelay = -1;
1130         private boolean mIsPersisted;
1131         // One-off parameters.
1132         private long mMinLatencyMillis;
1133         private long mMaxExecutionDelayMillis;
1134         // Periodic parameters.
1135         private boolean mIsPeriodic;
1136         private boolean mHasEarlyConstraint;
1137         private boolean mHasLateConstraint;
1138         private long mIntervalMillis;
1139         private long mFlexMillis;
1140         // Back-off parameters.
1141         private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS;
1142         private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY;
1143         /** Easy way to track whether the client has tried to set a back-off policy. */
1144         private boolean mBackoffPolicySet = false;
1145 
1146         /**
1147          * Initialize a new Builder to construct a {@link JobInfo}.
1148          *
1149          * @param jobId Application-provided id for this job. Subsequent calls to cancel, or
1150          * jobs created with the same jobId, will update the pre-existing job with
1151          * the same id.  This ID must be unique across all clients of the same uid
1152          * (not just the same package).  You will want to make sure this is a stable
1153          * id across app updates, so probably not based on a resource ID.
1154          * @param jobService The endpoint that you implement that will receive the callback from the
1155          * JobScheduler.
1156          */
Builder(int jobId, @NonNull ComponentName jobService)1157         public Builder(int jobId, @NonNull ComponentName jobService) {
1158             mJobService = jobService;
1159             mJobId = jobId;
1160         }
1161 
1162         /**
1163          * Creates a new Builder of JobInfo from an existing instance.
1164          * @hide
1165          */
Builder(@onNull JobInfo job)1166         public Builder(@NonNull JobInfo job) {
1167             mJobId = job.getId();
1168             mJobService = job.getService();
1169             mExtras = job.getExtras();
1170             mTransientExtras = job.getTransientExtras();
1171             mClipData = job.getClipData();
1172             mClipGrantFlags = job.getClipGrantFlags();
1173             mBias = job.getBias();
1174             mFlags = job.getFlags();
1175             mConstraintFlags = job.getConstraintFlags();
1176             mNetworkRequest = job.getRequiredNetwork();
1177             mNetworkDownloadBytes = job.getEstimatedNetworkDownloadBytes();
1178             mNetworkUploadBytes = job.getEstimatedNetworkUploadBytes();
1179             mMinimumNetworkChunkBytes = job.getMinimumNetworkChunkBytes();
1180             mTriggerContentUris = job.getTriggerContentUris() != null
1181                     ? new ArrayList<>(Arrays.asList(job.getTriggerContentUris())) : null;
1182             mTriggerContentUpdateDelay = job.getTriggerContentUpdateDelay();
1183             mTriggerContentMaxDelay = job.getTriggerContentMaxDelay();
1184             mIsPersisted = job.isPersisted();
1185             mMinLatencyMillis = job.getMinLatencyMillis();
1186             mMaxExecutionDelayMillis = job.getMaxExecutionDelayMillis();
1187             mIsPeriodic = job.isPeriodic();
1188             mHasEarlyConstraint = job.hasEarlyConstraint();
1189             mHasLateConstraint = job.hasLateConstraint();
1190             mIntervalMillis = job.getIntervalMillis();
1191             mFlexMillis = job.getFlexMillis();
1192             mInitialBackoffMillis = job.getInitialBackoffMillis();
1193             // mBackoffPolicySet isn't set but it's fine since this is copying from an already valid
1194             // job.
1195             mBackoffPolicy = job.getBackoffPolicy();
1196             mPriority = job.getPriority();
1197         }
1198 
1199         /** @hide */
1200         @NonNull
setBias(int bias)1201         public Builder setBias(int bias) {
1202             mBias = bias;
1203             return this;
1204         }
1205 
1206         /**
1207          * Indicate the priority for this job. The priority set here will be used to sort jobs
1208          * for the calling app and apply slightly different policies based on the priority.
1209          * The priority will <b>NOT</b> be used as a global sorting value to sort between
1210          * different app's jobs. Use this to inform the system about which jobs it should try
1211          * to run before other jobs. Giving the same priority to all of your jobs will result
1212          * in them all being treated the same. The priorities each have slightly different
1213          * behaviors, as noted in their relevant javadoc.
1214          *
1215          * <b>NOTE:</b> Setting all of your jobs to high priority will not be
1216          * beneficial to your app and in fact may hurt its performance in the
1217          * long run.
1218          *
1219          * In order to prevent starvation, repeatedly retried jobs (because of failures) will slowly
1220          * have their priorities lowered.
1221          *
1222          * @see JobInfo#getPriority()
1223          */
1224         @NonNull
setPriority(@riority int priority)1225         public Builder setPriority(@Priority int priority) {
1226             if (priority > PRIORITY_MAX || priority < PRIORITY_MIN) {
1227                 if (Compatibility.isChangeEnabled(THROW_ON_INVALID_PRIORITY_VALUE)) {
1228                     throw new IllegalArgumentException("Invalid priority value");
1229                 }
1230                 // No-op for invalid calls of apps that are targeting S-. This was an unsupported
1231                 // API before Tiramisu, so anyone calling this that isn't targeting T isn't
1232                 // guaranteed a behavior change.
1233                 return this;
1234             }
1235             mPriority = priority;
1236             return this;
1237         }
1238 
1239         /** @hide */
1240         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
setFlags(int flags)1241         public Builder setFlags(int flags) {
1242             mFlags = flags;
1243             return this;
1244         }
1245 
1246         /**
1247          * Set optional extras. This is persisted, so we only allow primitive types.
1248          * @param extras Bundle containing extras you want the scheduler to hold on to for you.
1249          * @see JobInfo#getExtras()
1250          */
setExtras(@onNull PersistableBundle extras)1251         public Builder setExtras(@NonNull PersistableBundle extras) {
1252             mExtras = extras;
1253             return this;
1254         }
1255 
1256         /**
1257          * Set optional transient extras.
1258          *
1259          * <p>Because setting this property is not compatible with persisted
1260          * jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
1261          * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
1262          *
1263          * @param extras Bundle containing extras you want the scheduler to hold on to for you.
1264          * @see JobInfo#getTransientExtras()
1265          */
setTransientExtras(@onNull Bundle extras)1266         public Builder setTransientExtras(@NonNull Bundle extras) {
1267             mTransientExtras = extras;
1268             return this;
1269         }
1270 
1271         /**
1272          * Set a {@link ClipData} associated with this Job.
1273          *
1274          * <p>The main purpose of providing a ClipData is to allow granting of
1275          * URI permissions for data associated with the clip.  The exact kind
1276          * of permission grant to perform is specified through <var>grantFlags</var>.
1277          *
1278          * <p>If the ClipData contains items that are Intents, any
1279          * grant flags in those Intents will be ignored.  Only flags provided as an argument
1280          * to this method are respected, and will be applied to all Uri or
1281          * Intent items in the clip (or sub-items of the clip).
1282          *
1283          * <p>Because setting this property is not compatible with persisted
1284          * jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
1285          * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
1286          *
1287          * @param clip The new clip to set.  May be null to clear the current clip.
1288          * @param grantFlags The desired permissions to grant for any URIs.  This should be
1289          * a combination of {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION},
1290          * {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, and
1291          * {@link android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION}.
1292          * @see JobInfo#getClipData()
1293          * @see JobInfo#getClipGrantFlags()
1294          */
setClipData(@ullable ClipData clip, int grantFlags)1295         public Builder setClipData(@Nullable ClipData clip, int grantFlags) {
1296             mClipData = clip;
1297             mClipGrantFlags = grantFlags;
1298             return this;
1299         }
1300 
1301         /**
1302          * Set basic description of the kind of network your job requires. If
1303          * you need more precise control over network capabilities, see
1304          * {@link #setRequiredNetwork(NetworkRequest)}.
1305          * <p>
1306          * If your job doesn't need a network connection, you don't need to call
1307          * this method, as the default value is {@link #NETWORK_TYPE_NONE}.
1308          * <p>
1309          * Calling this method defines network as a strict requirement for your
1310          * job. If the network requested is not available your job will never
1311          * run. See {@link #setOverrideDeadline(long)} to change this behavior.
1312          * Calling this method will override any requirements previously defined
1313          * by {@link #setRequiredNetwork(NetworkRequest)}; you typically only
1314          * want to call one of these methods.
1315          * <p class="note">
1316          * When your job executes in
1317          * {@link JobService#onStartJob(JobParameters)}, be sure to use the
1318          * specific network returned by {@link JobParameters#getNetwork()},
1319          * otherwise you'll use the default network which may not meet this
1320          * constraint.
1321          *
1322          * @see #setRequiredNetwork(NetworkRequest)
1323          * @see JobInfo#getNetworkType()
1324          * @see JobParameters#getNetwork()
1325          */
setRequiredNetworkType(@etworkType int networkType)1326         public Builder setRequiredNetworkType(@NetworkType int networkType) {
1327             if (networkType == NETWORK_TYPE_NONE) {
1328                 return setRequiredNetwork(null);
1329             } else {
1330                 final NetworkRequest.Builder builder = new NetworkRequest.Builder();
1331 
1332                 // All types require validated Internet
1333                 builder.addCapability(NET_CAPABILITY_INTERNET);
1334                 builder.addCapability(NET_CAPABILITY_VALIDATED);
1335                 builder.removeCapability(NET_CAPABILITY_NOT_VPN);
1336                 builder.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
1337 
1338                 if (networkType == NETWORK_TYPE_ANY) {
1339                     // No other capabilities
1340                 } else if (networkType == NETWORK_TYPE_UNMETERED) {
1341                     builder.addCapability(NET_CAPABILITY_NOT_METERED);
1342                 } else if (networkType == NETWORK_TYPE_NOT_ROAMING) {
1343                     builder.addCapability(NET_CAPABILITY_NOT_ROAMING);
1344                 } else if (networkType == NETWORK_TYPE_CELLULAR) {
1345                     builder.addTransportType(TRANSPORT_CELLULAR);
1346                 }
1347 
1348                 return setRequiredNetwork(builder.build());
1349             }
1350         }
1351 
1352         /**
1353          * Set detailed description of the kind of network your job requires.
1354          * <p>
1355          * If your job doesn't need a network connection, you don't need to call
1356          * this method, as the default is {@code null}.
1357          * <p>
1358          * Calling this method defines network as a strict requirement for your
1359          * job. If the network requested is not available your job will never
1360          * run. See {@link #setOverrideDeadline(long)} to change this behavior.
1361          * Calling this method will override any requirements previously defined
1362          * by {@link #setRequiredNetworkType(int)}; you typically only want to
1363          * call one of these methods.
1364          * <p class="note">
1365          * When your job executes in
1366          * {@link JobService#onStartJob(JobParameters)}, be sure to use the
1367          * specific network returned by {@link JobParameters#getNetwork()},
1368          * otherwise you'll use the default network which may not meet this
1369          * constraint.
1370          *
1371          * @param networkRequest The detailed description of the kind of network
1372          *            this job requires, or {@code null} if no specific kind of
1373          *            network is required. Defining a {@link NetworkSpecifier}
1374          *            is only supported for jobs that aren't persisted.
1375          * @see #setRequiredNetworkType(int)
1376          * @see JobInfo#getRequiredNetwork()
1377          * @see JobParameters#getNetwork()
1378          */
setRequiredNetwork(@ullable NetworkRequest networkRequest)1379         public Builder setRequiredNetwork(@Nullable NetworkRequest networkRequest) {
1380             mNetworkRequest = networkRequest;
1381             return this;
1382         }
1383 
1384         /**
1385          * Set the estimated size of network traffic that will be performed by
1386          * this job, in bytes.
1387          * <p>
1388          * Apps are encouraged to provide values that are as accurate as
1389          * possible, but when the exact size isn't available, an
1390          * order-of-magnitude estimate can be provided instead. Here are some
1391          * specific examples:
1392          * <ul>
1393          * <li>A job that is backing up a photo knows the exact size of that
1394          * photo, so it should provide that size as the estimate.
1395          * <li>A job that refreshes top news stories wouldn't know an exact
1396          * size, but if the size is expected to be consistently around 100KB, it
1397          * can provide that order-of-magnitude value as the estimate.
1398          * <li>A job that synchronizes email could end up using an extreme range
1399          * of data, from under 1KB when nothing has changed, to dozens of MB
1400          * when there are new emails with attachments. Jobs that cannot provide
1401          * reasonable estimates should use the sentinel value
1402          * {@link JobInfo#NETWORK_BYTES_UNKNOWN}.
1403          * </ul>
1404          * Note that the system may choose to delay jobs with large network
1405          * usage estimates when the device has a poor network connection, in
1406          * order to save battery and possible network costs.
1407          * Starting from Android version {@link Build.VERSION_CODES#S}, JobScheduler may attempt
1408          * to run large jobs when the device is charging and on an unmetered network, even if the
1409          * network is slow. This gives large jobs an opportunity to make forward progress, even if
1410          * they risk timing out.
1411          * <p>
1412          * The values provided here only reflect the traffic that will be
1413          * performed by the base job; if you're using {@link JobWorkItem} then
1414          * you also need to define the network traffic used by each work item
1415          * when constructing them.
1416          *
1417          * <p class="note">
1418          * Prior to Android version {@link Build.VERSION_CODES#TIRAMISU}, JobScheduler used the
1419          * estimated transfer numbers in a similar fashion to
1420          * {@link #setMinimumNetworkChunkBytes(long)} (to estimate if the work would complete
1421          * within the time available to job). In other words, JobScheduler treated the transfer as
1422          * all-or-nothing. Starting from Android version {@link Build.VERSION_CODES#TIRAMISU},
1423          * JobScheduler will only use the estimated transfer numbers in this manner if minimum
1424          * chunk sizes have not been provided via {@link #setMinimumNetworkChunkBytes(long)}.
1425          *
1426          * @param downloadBytes The estimated size of network traffic that will
1427          *            be downloaded by this job, in bytes.
1428          * @param uploadBytes The estimated size of network traffic that will be
1429          *            uploaded by this job, in bytes.
1430          * @see JobInfo#getEstimatedNetworkDownloadBytes()
1431          * @see JobInfo#getEstimatedNetworkUploadBytes()
1432          * @see JobWorkItem#JobWorkItem(android.content.Intent, long, long)
1433          */
setEstimatedNetworkBytes(@ytesLong long downloadBytes, @BytesLong long uploadBytes)1434         public Builder setEstimatedNetworkBytes(@BytesLong long downloadBytes,
1435                 @BytesLong long uploadBytes) {
1436             mNetworkDownloadBytes = downloadBytes;
1437             mNetworkUploadBytes = uploadBytes;
1438             return this;
1439         }
1440 
1441         /**
1442          * Set the minimum size of non-resumable network traffic this job requires, in bytes. When
1443          * the upload or download can be easily paused and resumed, use this to set the smallest
1444          * size that must be transmitted between start and stop events to be considered successful.
1445          * If the transfer cannot be paused and resumed, then this should be the sum of the values
1446          * provided to {@link JobInfo.Builder#setEstimatedNetworkBytes(long, long)}.
1447          *
1448          * <p>
1449          * Apps are encouraged to provide values that are as accurate as possible since JobScheduler
1450          * will try to run the job at a time when at least the minimum chunk can be transmitted to
1451          * reduce the amount of repetitive data that's transferred. Jobs that cannot provide
1452          * reasonable estimates should use the sentinel value {@link JobInfo#NETWORK_BYTES_UNKNOWN}.
1453          *
1454          * <p>
1455          * The values provided here only reflect the minimum non-resumable traffic that will be
1456          * performed by the base job; if you're using {@link JobWorkItem} then
1457          * you also need to define the network traffic used by each work item
1458          * when constructing them.
1459          *
1460          * @param chunkSizeBytes The smallest piece of data that cannot be easily paused and
1461          *                       resumed, in bytes.
1462          * @see JobInfo#getMinimumNetworkChunkBytes()
1463          * @see JobWorkItem#JobWorkItem(android.content.Intent, long, long, long)
1464          */
1465         @NonNull
setMinimumNetworkChunkBytes(@ytesLong long chunkSizeBytes)1466         public Builder setMinimumNetworkChunkBytes(@BytesLong long chunkSizeBytes) {
1467             if (chunkSizeBytes != NETWORK_BYTES_UNKNOWN && chunkSizeBytes <= 0) {
1468                 throw new IllegalArgumentException("Minimum chunk size must be positive");
1469             }
1470             mMinimumNetworkChunkBytes = chunkSizeBytes;
1471             return this;
1472         }
1473 
1474         /**
1475          * Specify that to run this job, the device must be charging (or be a
1476          * non-battery-powered device connected to permanent power, such as Android TV
1477          * devices). This defaults to {@code false}.
1478          *
1479          * <p class="note">For purposes of running jobs, a battery-powered device
1480          * "charging" is not quite the same as simply being connected to power.  If the
1481          * device is so busy that the battery is draining despite a power connection, jobs
1482          * with this constraint will <em>not</em> run.  This can happen during some
1483          * common use cases such as video chat, particularly if the device is plugged in
1484          * to USB rather than to wall power.
1485          *
1486          * @param requiresCharging Pass {@code true} to require that the device be
1487          *     charging in order to run the job.
1488          * @see JobInfo#isRequireCharging()
1489          */
setRequiresCharging(boolean requiresCharging)1490         public Builder setRequiresCharging(boolean requiresCharging) {
1491             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_CHARGING)
1492                     | (requiresCharging ? CONSTRAINT_FLAG_CHARGING : 0);
1493             return this;
1494         }
1495 
1496         /**
1497          * Specify that to run this job, the device's battery level must not be low.
1498          * This defaults to false.  If true, the job will only run when the battery level
1499          * is not low, which is generally the point where the user is given a "low battery"
1500          * warning.
1501          * @param batteryNotLow Whether or not the device's battery level must not be low.
1502          * @see JobInfo#isRequireBatteryNotLow()
1503          */
setRequiresBatteryNotLow(boolean batteryNotLow)1504         public Builder setRequiresBatteryNotLow(boolean batteryNotLow) {
1505             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_BATTERY_NOT_LOW)
1506                     | (batteryNotLow ? CONSTRAINT_FLAG_BATTERY_NOT_LOW : 0);
1507             return this;
1508         }
1509 
1510         /**
1511          * When set {@code true}, ensure that this job will not run if the device is in active use.
1512          * The default state is {@code false}: that is, the for the job to be runnable even when
1513          * someone is interacting with the device.
1514          *
1515          * <p>This state is a loose definition provided by the system. In general, it means that
1516          * the device is not currently being used interactively, and has not been in use for some
1517          * time. As such, it is a good time to perform resource heavy jobs. Bear in mind that
1518          * battery usage will still be attributed to your application, and surfaced to the user in
1519          * battery stats.</p>
1520          *
1521          * <p class="note">Despite the similar naming, this job constraint is <em>not</em>
1522          * related to the system's "device idle" or "doze" states.  This constraint only
1523          * determines whether a job is allowed to run while the device is directly in use.
1524          *
1525          * @param requiresDeviceIdle Pass {@code true} to prevent the job from running
1526          *     while the device is being used interactively.
1527          * @see JobInfo#isRequireDeviceIdle()
1528          */
setRequiresDeviceIdle(boolean requiresDeviceIdle)1529         public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
1530             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_DEVICE_IDLE)
1531                     | (requiresDeviceIdle ? CONSTRAINT_FLAG_DEVICE_IDLE : 0);
1532             return this;
1533         }
1534 
1535         /**
1536          * Specify that to run this job, the device's available storage must not be low.
1537          * This defaults to false.  If true, the job will only run when the device is not
1538          * in a low storage state, which is generally the point where the user is given a
1539          * "low storage" warning.
1540          * @param storageNotLow Whether or not the device's available storage must not be low.
1541          * @see JobInfo#isRequireStorageNotLow()
1542          */
setRequiresStorageNotLow(boolean storageNotLow)1543         public Builder setRequiresStorageNotLow(boolean storageNotLow) {
1544             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_STORAGE_NOT_LOW)
1545                     | (storageNotLow ? CONSTRAINT_FLAG_STORAGE_NOT_LOW : 0);
1546             return this;
1547         }
1548 
1549         /**
1550          * Add a new content: URI that will be monitored with a
1551          * {@link android.database.ContentObserver}, and will cause the job to execute if changed.
1552          * If you have any trigger content URIs associated with a job, it will not execute until
1553          * there has been a change report for one or more of them.
1554          *
1555          * <p>Note that trigger URIs can not be used in combination with
1556          * {@link #setPeriodic(long)} or {@link #setPersisted(boolean)}.  To continually monitor
1557          * for content changes, you need to schedule a new JobInfo using the same job ID and
1558          * observing the same URIs in place of calling
1559          * {@link JobService#jobFinished(JobParameters, boolean)}. Remember that
1560          * {@link JobScheduler#schedule(JobInfo)} stops a running job if it uses the same job ID,
1561          * so only call it after you've finished processing the most recent changes (in other words,
1562          * call {@link JobScheduler#schedule(JobInfo)} where you would have normally called
1563          * {@link JobService#jobFinished(JobParameters, boolean)}.
1564          * Following this pattern will ensure you do not lose any content changes: while your
1565          * job is running, the system will continue monitoring for content changes, and propagate
1566          * any changes it sees over to the next job you schedule, so you do not have to worry
1567          * about missing new changes. <b>Scheduling the new job
1568          * before or during processing will cause the current job to be stopped (as described in
1569          * {@link JobScheduler#schedule(JobInfo)}), meaning the wakelock will be released for the
1570          * current job and your app process may be killed since it will no longer be in a valid
1571          * component lifecycle.</b>
1572          * Since {@link JobScheduler#schedule(JobInfo)} stops the current job, you do not
1573          * need to call {@link JobService#jobFinished(JobParameters, boolean)} if you call
1574          * {@link JobScheduler#schedule(JobInfo)} using the same job ID as the
1575          * currently running job.</p>
1576          *
1577          * <p>Because setting this property is not compatible with periodic or
1578          * persisted jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
1579          * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
1580          *
1581          * <p>The following example shows how this feature can be used to monitor for changes
1582          * in the photos on a device.</p>
1583          *
1584          * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/PhotosContentJob.java
1585          *      job}
1586          *
1587          * @param uri The content: URI to monitor.
1588          * @see JobInfo#getTriggerContentUris()
1589          */
addTriggerContentUri(@onNull TriggerContentUri uri)1590         public Builder addTriggerContentUri(@NonNull TriggerContentUri uri) {
1591             if (mTriggerContentUris == null) {
1592                 mTriggerContentUris = new ArrayList<>();
1593             }
1594             mTriggerContentUris.add(uri);
1595             return this;
1596         }
1597 
1598         /**
1599          * Set the delay (in milliseconds) from when a content change is detected until
1600          * the job is scheduled.  If there are more changes during that time, the delay
1601          * will be reset to start at the time of the most recent change.
1602          * @param durationMs Delay after most recent content change, in milliseconds.
1603          * @see JobInfo#getTriggerContentUpdateDelay()
1604          */
setTriggerContentUpdateDelay(long durationMs)1605         public Builder setTriggerContentUpdateDelay(long durationMs) {
1606             mTriggerContentUpdateDelay = durationMs;
1607             return this;
1608         }
1609 
1610         /**
1611          * Set the maximum total delay (in milliseconds) that is allowed from the first
1612          * time a content change is detected until the job is scheduled.
1613          * @param durationMs Delay after initial content change, in milliseconds.
1614          * @see JobInfo#getTriggerContentMaxDelay()
1615          */
setTriggerContentMaxDelay(long durationMs)1616         public Builder setTriggerContentMaxDelay(long durationMs) {
1617             mTriggerContentMaxDelay = durationMs;
1618             return this;
1619         }
1620 
1621         /**
1622          * Specify that this job should recur with the provided interval, not more than once per
1623          * period. You have no control over when within this interval this job will be executed,
1624          * only the guarantee that it will be executed at most once within this interval, as long
1625          * as the constraints are satisfied. If the constraints are not satisfied within this
1626          * interval, the job will wait until the constraints are satisfied.
1627          * Setting this function on the builder with {@link #setMinimumLatency(long)} or
1628          * {@link #setOverrideDeadline(long)} will result in an error.
1629          * @param intervalMillis Millisecond interval for which this job will repeat.
1630          * @see JobInfo#getIntervalMillis()
1631          * @see JobInfo#getFlexMillis()
1632          */
setPeriodic(long intervalMillis)1633         public Builder setPeriodic(long intervalMillis) {
1634             return setPeriodic(intervalMillis, intervalMillis);
1635         }
1636 
1637         /**
1638          * Specify that this job should recur with the provided interval and flex. The job can
1639          * execute at any time in a window of flex length at the end of the period.
1640          * @param intervalMillis Millisecond interval for which this job will repeat. A minimum
1641          *                       value of {@link #getMinPeriodMillis()} is enforced.
1642          * @param flexMillis Millisecond flex for this job. Flex is clamped to be at least
1643          *                   {@link #getMinFlexMillis()} or 5 percent of the period, whichever is
1644          *                   higher.
1645          * @see JobInfo#getIntervalMillis()
1646          * @see JobInfo#getFlexMillis()
1647          */
setPeriodic(long intervalMillis, long flexMillis)1648         public Builder setPeriodic(long intervalMillis, long flexMillis) {
1649             final long minPeriod = getMinPeriodMillis();
1650             if (intervalMillis < minPeriod) {
1651                 Log.w(TAG, "Requested interval " + formatDuration(intervalMillis) + " for job "
1652                         + mJobId + " is too small; raising to " + formatDuration(minPeriod));
1653                 intervalMillis = minPeriod;
1654             }
1655 
1656             final long percentClamp = 5 * intervalMillis / 100;
1657             final long minFlex = Math.max(percentClamp, getMinFlexMillis());
1658             if (flexMillis < minFlex) {
1659                 Log.w(TAG, "Requested flex " + formatDuration(flexMillis) + " for job " + mJobId
1660                         + " is too small; raising to " + formatDuration(minFlex));
1661                 flexMillis = minFlex;
1662             }
1663 
1664             mIsPeriodic = true;
1665             mIntervalMillis = intervalMillis;
1666             mFlexMillis = flexMillis;
1667             mHasEarlyConstraint = mHasLateConstraint = true;
1668             return this;
1669         }
1670 
1671         /**
1672          * Specify that this job should be delayed by the provided amount of time. The job may not
1673          * run the instant the delay has elapsed. JobScheduler will start the job at an
1674          * indeterminate time after the delay has elapsed.
1675          * <p>
1676          * Because it doesn't make sense setting this property on a periodic job, doing so will
1677          * throw an {@link java.lang.IllegalArgumentException} when
1678          * {@link android.app.job.JobInfo.Builder#build()} is called.
1679          * @param minLatencyMillis Milliseconds before which this job will not be considered for
1680          *                         execution.
1681          * @see JobInfo#getMinLatencyMillis()
1682          */
setMinimumLatency(long minLatencyMillis)1683         public Builder setMinimumLatency(long minLatencyMillis) {
1684             mMinLatencyMillis = minLatencyMillis;
1685             mHasEarlyConstraint = true;
1686             return this;
1687         }
1688 
1689         /**
1690          * Set deadline which is the maximum scheduling latency. The job will be run by this
1691          * deadline even if other requirements (including a delay set through
1692          * {@link #setMinimumLatency(long)}) are not met.
1693          * <p>
1694          * Because it doesn't make sense setting this property on a periodic job, doing so will
1695          * throw an {@link java.lang.IllegalArgumentException} when
1696          * {@link android.app.job.JobInfo.Builder#build()} is called.
1697          * @see JobInfo#getMaxExecutionDelayMillis()
1698          */
setOverrideDeadline(long maxExecutionDelayMillis)1699         public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
1700             mMaxExecutionDelayMillis = maxExecutionDelayMillis;
1701             mHasLateConstraint = true;
1702             return this;
1703         }
1704 
1705         /**
1706          * Set up the back-off/retry policy.
1707          * This defaults to some respectable values: {30 seconds, Exponential}. We cap back-off at
1708          * 5hrs.
1709          * <p>
1710          * Note that trying to set a backoff criteria for a job with
1711          * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
1712          * This is because back-off typically does not make sense for these types of jobs. See
1713          * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
1714          * for more description of the return value for the case of a job executing while in idle
1715          * mode.
1716          * @param initialBackoffMillis Millisecond time interval to wait initially when job has
1717          *                             failed.
1718          * @see JobInfo#getInitialBackoffMillis()
1719          * @see JobInfo#getBackoffPolicy()
1720          */
setBackoffCriteria(long initialBackoffMillis, @BackoffPolicy int backoffPolicy)1721         public Builder setBackoffCriteria(long initialBackoffMillis,
1722                 @BackoffPolicy int backoffPolicy) {
1723             final long minBackoff = getMinBackoffMillis();
1724             if (initialBackoffMillis < minBackoff) {
1725                 Log.w(TAG, "Requested backoff " + formatDuration(initialBackoffMillis) + " for job "
1726                         + mJobId + " is too small; raising to " + formatDuration(minBackoff));
1727                 initialBackoffMillis = minBackoff;
1728             }
1729 
1730             mBackoffPolicySet = true;
1731             mInitialBackoffMillis = initialBackoffMillis;
1732             mBackoffPolicy = backoffPolicy;
1733             return this;
1734         }
1735 
1736         /**
1737          * Setting this to true indicates that this job is important and needs to run as soon as
1738          * possible with stronger guarantees than regular jobs. These "expedited" jobs will:
1739          * <ol>
1740          *     <li>Run as soon as possible</li>
1741          *     <li>Be less restricted during Doze and battery saver</li>
1742          *     <li>Bypass Doze, app standby, and battery saver network restrictions</li>
1743          *     <li>Be less likely to be killed than regular jobs</li>
1744          *     <li>Be subject to background location throttling</li>
1745          * </ol>
1746          *
1747          * <p>
1748          * Since these jobs have stronger guarantees than regular jobs, they will be subject to
1749          * stricter quotas. As long as an app has available expedited quota, jobs scheduled with
1750          * this set to true will run with these guarantees. If an app has run out of available
1751          * expedited quota, any pending expedited jobs will run as regular jobs.
1752          * {@link JobParameters#isExpeditedJob()} can be used to know whether the executing job
1753          * has expedited guarantees or not. In addition, {@link JobScheduler#schedule(JobInfo)}
1754          * will immediately return {@link JobScheduler#RESULT_FAILURE} if the app does not have
1755          * available quota (and the job will not be successfully scheduled).
1756          *
1757          * <p>
1758          * Expedited job quota will replenish over time and as the user interacts with the app,
1759          * so you should not have to worry about running out of quota because of processing from
1760          * frequent user engagement.
1761          *
1762          * <p>
1763          * Expedited jobs may only set network, storage-not-low, and persistence constraints.
1764          * No other constraints are allowed.
1765          *
1766          * <p>
1767          * Assuming all constraints remain satisfied (including ideal system load conditions),
1768          * expedited jobs can have an execution time of at least 1 minute. If your
1769          * app has remaining expedited job quota, then the expedited job <i>may</i> potentially run
1770          * longer until remaining quota is used up. Just like with regular jobs, quota is not
1771          * consumed while the app is on top and visible to the user.
1772          *
1773          * <p class="note">
1774          * Note: Even though expedited jobs are meant to run as soon as possible, they may be
1775          * deferred if the system is under heavy load or requested constraints are not satisfied.
1776          * This delay may be true for expedited jobs of the foreground app on Android version
1777          * {@link Build.VERSION_CODES#S}, but starting from Android version
1778          * {@link Build.VERSION_CODES#TIRAMISU}, expedited jobs for the foreground app are
1779          * guaranteed to be started before {@link JobScheduler#schedule(JobInfo)} returns (assuming
1780          * all requested constraints are satisfied), similar to foreground services.
1781          *
1782          * @see JobInfo#isExpedited()
1783          */
1784         @NonNull
setExpedited(boolean expedited)1785         public Builder setExpedited(boolean expedited) {
1786             if (expedited) {
1787                 mFlags |= FLAG_EXPEDITED;
1788                 if (mPriority == PRIORITY_DEFAULT) {
1789                     // The default priority for EJs is MAX, but only change this if .setPriority()
1790                     // hasn't been called yet.
1791                     mPriority = PRIORITY_MAX;
1792                 }
1793             } else {
1794                 if (mPriority == PRIORITY_MAX && (mFlags & FLAG_EXPEDITED) != 0) {
1795                     // Reset the priority for the job, but only change this if .setPriority()
1796                     // hasn't been called yet.
1797                     mPriority = PRIORITY_DEFAULT;
1798                 }
1799                 mFlags &= (~FLAG_EXPEDITED);
1800             }
1801             return this;
1802         }
1803 
1804         /**
1805          * Setting this to true indicates that this job is important while the scheduling app
1806          * is in the foreground or on the temporary whitelist for background restrictions.
1807          * This means that the system will relax doze restrictions on this job during this time.
1808          *
1809          * Apps should use this flag only for short jobs that are essential for the app to function
1810          * properly in the foreground.
1811          *
1812          * Note that once the scheduling app is no longer whitelisted from background restrictions
1813          * and in the background, or the job failed due to unsatisfied constraints,
1814          * this job should be expected to behave like other jobs without this flag.
1815          *
1816          * <p>
1817          * Jobs marked as important-while-foreground are given {@link #PRIORITY_HIGH} by default.
1818          *
1819          * @param importantWhileForeground whether to relax doze restrictions for this job when the
1820          *                                 app is in the foreground. False by default.
1821          * @see JobInfo#isImportantWhileForeground()
1822          * @deprecated Use {@link #setExpedited(boolean)} instead.
1823          */
1824         @Deprecated
setImportantWhileForeground(boolean importantWhileForeground)1825         public Builder setImportantWhileForeground(boolean importantWhileForeground) {
1826             if (importantWhileForeground) {
1827                 mFlags |= FLAG_IMPORTANT_WHILE_FOREGROUND;
1828                 if (mPriority == PRIORITY_DEFAULT) {
1829                     // The default priority for important-while-foreground is HIGH, but only change
1830                     // this if .setPriority() hasn't been called yet.
1831                     mPriority = PRIORITY_HIGH;
1832                 }
1833             } else {
1834                 if (mPriority == PRIORITY_HIGH
1835                         && (mFlags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0) {
1836                     // Reset the priority for the job, but only change this if .setPriority()
1837                     // hasn't been called yet.
1838                     mPriority = PRIORITY_DEFAULT;
1839                 }
1840                 mFlags &= (~FLAG_IMPORTANT_WHILE_FOREGROUND);
1841             }
1842             return this;
1843         }
1844 
1845         /**
1846          * Setting this to true indicates that this job is designed to prefetch
1847          * content that will make a material improvement to the experience of
1848          * the specific user of this device. For example, fetching top headlines
1849          * of interest to the current user.
1850          * <p>
1851          * Apps targeting Android version {@link Build.VERSION_CODES#TIRAMISU} or later are
1852          * not allowed to have deadlines (set via {@link #setOverrideDeadline(long)} on their
1853          * prefetch jobs.
1854          * <p>
1855          * The system may use this signal to relax the network constraints you
1856          * originally requested, such as allowing a
1857          * {@link JobInfo#NETWORK_TYPE_UNMETERED} job to run over a metered
1858          * network when there is a surplus of metered data available. The system
1859          * may also use this signal in combination with end user usage patterns
1860          * to ensure data is prefetched before the user launches your app.
1861          * @see JobInfo#isPrefetch()
1862          */
setPrefetch(boolean prefetch)1863         public Builder setPrefetch(boolean prefetch) {
1864             if (prefetch) {
1865                 mFlags |= FLAG_PREFETCH;
1866             } else {
1867                 mFlags &= (~FLAG_PREFETCH);
1868             }
1869             return this;
1870         }
1871 
1872         /**
1873          * Set whether or not to persist this job across device reboots.
1874          *
1875          * @param isPersisted True to indicate that the job will be written to
1876          *            disk and loaded at boot.
1877          * @see JobInfo#isPersisted()
1878          */
1879         @RequiresPermission(android.Manifest.permission.RECEIVE_BOOT_COMPLETED)
setPersisted(boolean isPersisted)1880         public Builder setPersisted(boolean isPersisted) {
1881             mIsPersisted = isPersisted;
1882             return this;
1883         }
1884 
1885         /**
1886          * @return The job object to hand to the JobScheduler. This object is immutable.
1887          */
build()1888         public JobInfo build() {
1889             return build(Compatibility.isChangeEnabled(DISALLOW_DEADLINES_FOR_PREFETCH_JOBS));
1890         }
1891 
1892         /** @hide */
build(boolean disallowPrefetchDeadlines)1893         public JobInfo build(boolean disallowPrefetchDeadlines) {
1894             // This check doesn't need to be inside enforceValidity. It's an unnecessary legacy
1895             // check that would ideally be phased out instead.
1896             if (mBackoffPolicySet && (mConstraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0) {
1897                 throw new IllegalArgumentException("An idle mode job will not respect any" +
1898                         " back-off policy, so calling setBackoffCriteria with" +
1899                         " setRequiresDeviceIdle is an error.");
1900             }
1901             JobInfo jobInfo = new JobInfo(this);
1902             jobInfo.enforceValidity(disallowPrefetchDeadlines);
1903             return jobInfo;
1904         }
1905 
1906         /**
1907          * @hide
1908          */
summarize()1909         public String summarize() {
1910             final String service = (mJobService != null)
1911                     ? mJobService.flattenToShortString()
1912                     : "null";
1913             return "JobInfo.Builder{job:" + mJobId + "/" + service + "}";
1914         }
1915     }
1916 
1917     /**
1918      * @hide
1919      */
enforceValidity(boolean disallowPrefetchDeadlines)1920     public final void enforceValidity(boolean disallowPrefetchDeadlines) {
1921         // Check that network estimates require network type and are reasonable values.
1922         if ((networkDownloadBytes > 0 || networkUploadBytes > 0 || minimumNetworkChunkBytes > 0)
1923                 && networkRequest == null) {
1924             throw new IllegalArgumentException(
1925                     "Can't provide estimated network usage without requiring a network");
1926         }
1927         final long estimatedTransfer;
1928         if (networkUploadBytes == NETWORK_BYTES_UNKNOWN) {
1929             estimatedTransfer = networkDownloadBytes;
1930         } else {
1931             estimatedTransfer = networkUploadBytes
1932                     + (networkDownloadBytes == NETWORK_BYTES_UNKNOWN ? 0 : networkDownloadBytes);
1933         }
1934         if (minimumNetworkChunkBytes != NETWORK_BYTES_UNKNOWN
1935                 && estimatedTransfer != NETWORK_BYTES_UNKNOWN
1936                 && minimumNetworkChunkBytes > estimatedTransfer) {
1937             throw new IllegalArgumentException(
1938                     "Minimum chunk size can't be greater than estimated network usage");
1939         }
1940         if (minimumNetworkChunkBytes != NETWORK_BYTES_UNKNOWN && minimumNetworkChunkBytes <= 0) {
1941             throw new IllegalArgumentException("Minimum chunk size must be positive");
1942         }
1943 
1944         final boolean hasDeadline = maxExecutionDelayMillis != 0L;
1945         // Check that a deadline was not set on a periodic job.
1946         if (isPeriodic) {
1947             if (hasDeadline) {
1948                 throw new IllegalArgumentException(
1949                         "Can't call setOverrideDeadline() on a periodic job.");
1950             }
1951             if (minLatencyMillis != 0L) {
1952                 throw new IllegalArgumentException(
1953                         "Can't call setMinimumLatency() on a periodic job");
1954             }
1955             if (triggerContentUris != null) {
1956                 throw new IllegalArgumentException(
1957                         "Can't call addTriggerContentUri() on a periodic job");
1958             }
1959         }
1960 
1961         // Prefetch jobs should not have deadlines
1962         if (disallowPrefetchDeadlines && hasDeadline && (flags & FLAG_PREFETCH) != 0) {
1963             throw new IllegalArgumentException(
1964                     "Can't call setOverrideDeadline() on a prefetch job.");
1965         }
1966 
1967         if (isPersisted) {
1968             // We can't serialize network specifiers
1969             if (networkRequest != null
1970                     && networkRequest.getNetworkSpecifier() != null) {
1971                 throw new IllegalArgumentException(
1972                         "Network specifiers aren't supported for persistent jobs");
1973             }
1974             if (triggerContentUris != null) {
1975                 throw new IllegalArgumentException(
1976                         "Can't call addTriggerContentUri() on a persisted job");
1977             }
1978             if (!transientExtras.isEmpty()) {
1979                 throw new IllegalArgumentException(
1980                         "Can't call setTransientExtras() on a persisted job");
1981             }
1982             if (clipData != null) {
1983                 throw new IllegalArgumentException(
1984                         "Can't call setClipData() on a persisted job");
1985             }
1986         }
1987 
1988         if ((flags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0) {
1989             if (hasEarlyConstraint) {
1990                 throw new IllegalArgumentException(
1991                         "An important while foreground job cannot have a time delay");
1992             }
1993             if (mPriority != PRIORITY_HIGH && mPriority != PRIORITY_DEFAULT) {
1994                 throw new IllegalArgumentException(
1995                         "An important while foreground job must be high or default priority."
1996                                 + " Don't mark unimportant tasks as important while foreground.");
1997             }
1998         }
1999 
2000         final boolean isExpedited = (flags & FLAG_EXPEDITED) != 0;
2001         switch (mPriority) {
2002             case PRIORITY_MAX:
2003                 if (!isExpedited) {
2004                     throw new IllegalArgumentException("Only expedited jobs can have max priority");
2005                 }
2006                 break;
2007             case PRIORITY_HIGH:
2008                 if ((flags & FLAG_PREFETCH) != 0) {
2009                     throw new IllegalArgumentException("Prefetch jobs cannot be high priority");
2010                 }
2011                 if (isPeriodic) {
2012                     throw new IllegalArgumentException("Periodic jobs cannot be high priority");
2013                 }
2014                 break;
2015             case PRIORITY_DEFAULT:
2016             case PRIORITY_LOW:
2017             case PRIORITY_MIN:
2018                 break;
2019             default:
2020                 throw new IllegalArgumentException("Invalid priority level provided: " + mPriority);
2021         }
2022 
2023         if (isExpedited) {
2024             if (hasEarlyConstraint) {
2025                 throw new IllegalArgumentException("An expedited job cannot have a time delay");
2026             }
2027             if (hasLateConstraint) {
2028                 throw new IllegalArgumentException("An expedited job cannot have a deadline");
2029             }
2030             if (isPeriodic) {
2031                 throw new IllegalArgumentException("An expedited job cannot be periodic");
2032             }
2033             if (mPriority != PRIORITY_MAX && mPriority != PRIORITY_HIGH) {
2034                 throw new IllegalArgumentException(
2035                         "An expedited job must be high or max priority. Don't use expedited jobs"
2036                                 + " for unimportant tasks.");
2037             }
2038             if ((constraintFlags & ~CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0
2039                     || (flags & ~(FLAG_EXPEDITED | FLAG_EXEMPT_FROM_APP_STANDBY)) != 0) {
2040                 throw new IllegalArgumentException(
2041                         "An expedited job can only have network and storage-not-low constraints");
2042             }
2043             if (triggerContentUris != null && triggerContentUris.length > 0) {
2044                 throw new IllegalArgumentException(
2045                         "Can't call addTriggerContentUri() on an expedited job");
2046             }
2047         }
2048     }
2049 
2050     /**
2051      * Convert a bias integer into a human readable string for debugging.
2052      * @hide
2053      */
getBiasString(int bias)2054     public static String getBiasString(int bias) {
2055         switch (bias) {
2056             case BIAS_DEFAULT:
2057                 return BIAS_DEFAULT + " [DEFAULT]";
2058             case BIAS_SYNC_EXPEDITED:
2059                 return BIAS_SYNC_EXPEDITED + " [SYNC_EXPEDITED]";
2060             case BIAS_SYNC_INITIALIZATION:
2061                 return BIAS_SYNC_INITIALIZATION + " [SYNC_INITIALIZATION]";
2062             case BIAS_BOUND_FOREGROUND_SERVICE:
2063                 return BIAS_BOUND_FOREGROUND_SERVICE + " [BFGS_APP]";
2064             case BIAS_FOREGROUND_SERVICE:
2065                 return BIAS_FOREGROUND_SERVICE + " [FGS_APP]";
2066             case BIAS_TOP_APP:
2067                 return BIAS_TOP_APP + " [TOP_APP]";
2068 
2069                 // BIAS_ADJ_* are adjustments and not used as real priorities.
2070                 // No need to convert to strings.
2071         }
2072         return bias + " [UNKNOWN]";
2073     }
2074 
2075     /**
2076      * Convert a priority integer into a human readable string for debugging.
2077      * @hide
2078      */
getPriorityString(@riority int priority)2079     public static String getPriorityString(@Priority int priority) {
2080         switch (priority) {
2081             case PRIORITY_MIN:
2082                 return priority + " [MIN]";
2083             case PRIORITY_LOW:
2084                 return priority + " [LOW]";
2085             case PRIORITY_DEFAULT:
2086                 return priority + " [DEFAULT]";
2087             case PRIORITY_HIGH:
2088                 return priority + " [HIGH]";
2089             case PRIORITY_MAX:
2090                 return priority + " [MAX]";
2091         }
2092         return priority + " [UNKNOWN]";
2093     }
2094 }
2095