• 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_ROAMING;
22 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
23 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
24 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
25 import static android.util.TimeUtils.formatDuration;
26 
27 import android.annotation.BytesLong;
28 import android.annotation.IntDef;
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.annotation.RequiresPermission;
32 import android.annotation.UnsupportedAppUsage;
33 import android.content.ClipData;
34 import android.content.ComponentName;
35 import android.net.NetworkRequest;
36 import android.net.NetworkSpecifier;
37 import android.net.Uri;
38 import android.os.BaseBundle;
39 import android.os.Build;
40 import android.os.Bundle;
41 import android.os.Parcel;
42 import android.os.Parcelable;
43 import android.os.PersistableBundle;
44 import android.util.Log;
45 
46 import java.lang.annotation.Retention;
47 import java.lang.annotation.RetentionPolicy;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.Objects;
51 
52 /**
53  * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
54  * parameters required to schedule work against the calling application. These are constructed
55  * using the {@link JobInfo.Builder}.
56  * You must specify at least one sort of constraint on the JobInfo object that you are creating.
57  * The goal here is to provide the scheduler with high-level semantics about the work you want to
58  * accomplish. Doing otherwise with throw an exception in your app.
59  */
60 public class JobInfo implements Parcelable {
61     private static String TAG = "JobInfo";
62 
63     /** @hide */
64     @IntDef(prefix = { "NETWORK_TYPE_" }, value = {
65             NETWORK_TYPE_NONE,
66             NETWORK_TYPE_ANY,
67             NETWORK_TYPE_UNMETERED,
68             NETWORK_TYPE_NOT_ROAMING,
69             NETWORK_TYPE_CELLULAR,
70     })
71     @Retention(RetentionPolicy.SOURCE)
72     public @interface NetworkType {}
73 
74     /** Default. */
75     public static final int NETWORK_TYPE_NONE = 0;
76     /** This job requires network connectivity. */
77     public static final int NETWORK_TYPE_ANY = 1;
78     /** This job requires network connectivity that is unmetered. */
79     public static final int NETWORK_TYPE_UNMETERED = 2;
80     /** This job requires network connectivity that is not roaming. */
81     public static final int NETWORK_TYPE_NOT_ROAMING = 3;
82     /** This job requires network connectivity that is a cellular network. */
83     public static final int NETWORK_TYPE_CELLULAR = 4;
84 
85     /**
86      * This job requires metered connectivity such as most cellular data
87      * networks.
88      *
89      * @deprecated Cellular networks may be unmetered, or Wi-Fi networks may be
90      *             metered, so this isn't a good way of selecting a specific
91      *             transport. Instead, use {@link #NETWORK_TYPE_CELLULAR} or
92      *             {@link android.net.NetworkRequest.Builder#addTransportType(int)}
93      *             if your job requires a specific network transport.
94      */
95     @Deprecated
96     public static final int NETWORK_TYPE_METERED = NETWORK_TYPE_CELLULAR;
97 
98     /** Sentinel value indicating that bytes are unknown. */
99     public static final int NETWORK_BYTES_UNKNOWN = -1;
100 
101     /**
102      * Amount of backoff a job has initially by default, in milliseconds.
103      */
104     public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L;  // 30 seconds.
105 
106     /**
107      * Maximum backoff we allow for a job, in milliseconds.
108      */
109     public static final long MAX_BACKOFF_DELAY_MILLIS = 5 * 60 * 60 * 1000;  // 5 hours.
110 
111     /** @hide */
112     @IntDef(prefix = { "BACKOFF_POLICY_" }, value = {
113             BACKOFF_POLICY_LINEAR,
114             BACKOFF_POLICY_EXPONENTIAL,
115     })
116     @Retention(RetentionPolicy.SOURCE)
117     public @interface BackoffPolicy {}
118 
119     /**
120      * Linearly back-off a failed job. See
121      * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}
122      * retry_time(current_time, num_failures) =
123      *     current_time + initial_backoff_millis * num_failures, num_failures >= 1
124      */
125     public static final int BACKOFF_POLICY_LINEAR = 0;
126 
127     /**
128      * Exponentially back-off a failed job. See
129      * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}
130      *
131      * retry_time(current_time, num_failures) =
132      *     current_time + initial_backoff_millis * 2 ^ (num_failures - 1), num_failures >= 1
133      */
134     public static final int BACKOFF_POLICY_EXPONENTIAL = 1;
135 
136     /* Minimum interval for a periodic job, in milliseconds. */
137     private static final long MIN_PERIOD_MILLIS = 15 * 60 * 1000L;   // 15 minutes
138 
139     /* Minimum flex for a periodic job, in milliseconds. */
140     private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
141 
142     /**
143      * Minimum backoff interval for a job, in milliseconds
144      * @hide
145      */
146     public static final long MIN_BACKOFF_MILLIS = 10 * 1000L;      // 10 seconds
147 
148     /**
149      * Query the minimum interval allowed for periodic scheduled jobs.  Attempting
150      * to declare a smaller period that this when scheduling a job will result in a
151      * job that is still periodic, but will run with this effective period.
152      *
153      * @return The minimum available interval for scheduling periodic jobs, in milliseconds.
154      */
getMinPeriodMillis()155     public static final long getMinPeriodMillis() {
156         return MIN_PERIOD_MILLIS;
157     }
158 
159     /**
160      * Query the minimum flex time allowed for periodic scheduled jobs.  Attempting
161      * to declare a shorter flex time than this when scheduling such a job will
162      * result in this amount as the effective flex time for the job.
163      *
164      * @return The minimum available flex time for scheduling periodic jobs, in milliseconds.
165      */
getMinFlexMillis()166     public static final long getMinFlexMillis() {
167         return MIN_FLEX_MILLIS;
168     }
169 
170     /**
171      * Query the minimum automatic-reschedule backoff interval permitted for jobs.
172      * @hide
173      */
getMinBackoffMillis()174     public static final long getMinBackoffMillis() {
175         return MIN_BACKOFF_MILLIS;
176     }
177 
178     /**
179      * Default type of backoff.
180      * @hide
181      */
182     public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL;
183 
184     /**
185      * Default of {@link #getPriority}.
186      * @hide
187      */
188     public static final int PRIORITY_DEFAULT = 0;
189 
190     /**
191      * Value of {@link #getPriority} for expedited syncs.
192      * @hide
193      */
194     public static final int PRIORITY_SYNC_EXPEDITED = 10;
195 
196     /**
197      * Value of {@link #getPriority} for first time initialization syncs.
198      * @hide
199      */
200     public static final int PRIORITY_SYNC_INITIALIZATION = 20;
201 
202     /**
203      * Value of {@link #getPriority} for a BFGS app (overrides the supplied
204      * JobInfo priority if it is smaller).
205      * @hide
206      */
207     public static final int PRIORITY_BOUND_FOREGROUND_SERVICE = 30;
208 
209     /** @hide For backward compatibility. */
210     @UnsupportedAppUsage
211     public static final int PRIORITY_FOREGROUND_APP = PRIORITY_BOUND_FOREGROUND_SERVICE;
212 
213     /**
214      * Value of {@link #getPriority} for a FG service app (overrides the supplied
215      * JobInfo priority if it is smaller).
216      * @hide
217      */
218     @UnsupportedAppUsage
219     public static final int PRIORITY_FOREGROUND_SERVICE = 35;
220 
221     /**
222      * Value of {@link #getPriority} for the current top app (overrides the supplied
223      * JobInfo priority if it is smaller).
224      * @hide
225      */
226     public static final int PRIORITY_TOP_APP = 40;
227 
228     /**
229      * Adjustment of {@link #getPriority} if the app has often (50% or more of the time)
230      * been running jobs.
231      * @hide
232      */
233     public static final int PRIORITY_ADJ_OFTEN_RUNNING = -40;
234 
235     /**
236      * Adjustment of {@link #getPriority} if the app has always (90% or more of the time)
237      * been running jobs.
238      * @hide
239      */
240     public static final int PRIORITY_ADJ_ALWAYS_RUNNING = -80;
241 
242     /**
243      * Indicates that the implementation of this job will be using
244      * {@link JobService#startForeground(int, android.app.Notification)} to run
245      * in the foreground.
246      * <p>
247      * When set, the internal scheduling of this job will ignore any background
248      * network restrictions for the requesting app. Note that this flag alone
249      * doesn't actually place your {@link JobService} in the foreground; you
250      * still need to post the notification yourself.
251      * <p>
252      * To use this flag, the caller must hold the
253      * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL} permission.
254      *
255      * @hide
256      */
257     @UnsupportedAppUsage
258     public static final int FLAG_WILL_BE_FOREGROUND = 1 << 0;
259 
260     /**
261      * Allows this job to run despite doze restrictions as long as the app is in the foreground
262      * or on the temporary whitelist
263      * @hide
264      */
265     public static final int FLAG_IMPORTANT_WHILE_FOREGROUND = 1 << 1;
266 
267     /**
268      * @hide
269      */
270     public static final int FLAG_PREFETCH = 1 << 2;
271 
272     /**
273      * This job needs to be exempted from the app standby throttling. Only the system (UID 1000)
274      * can set it. Jobs with a time constrant must not have it.
275      *
276      * @hide
277      */
278     public static final int FLAG_EXEMPT_FROM_APP_STANDBY = 1 << 3;
279 
280     /**
281      * @hide
282      */
283     public static final int CONSTRAINT_FLAG_CHARGING = 1 << 0;
284 
285     /**
286      * @hide
287      */
288     public static final int CONSTRAINT_FLAG_BATTERY_NOT_LOW = 1 << 1;
289 
290     /**
291      * @hide
292      */
293     public static final int CONSTRAINT_FLAG_DEVICE_IDLE = 1 << 2;
294 
295     /**
296      * @hide
297      */
298     public static final int CONSTRAINT_FLAG_STORAGE_NOT_LOW = 1 << 3;
299 
300     @UnsupportedAppUsage
301     private final int jobId;
302     private final PersistableBundle extras;
303     private final Bundle transientExtras;
304     private final ClipData clipData;
305     private final int clipGrantFlags;
306     @UnsupportedAppUsage
307     private final ComponentName service;
308     private final int constraintFlags;
309     private final TriggerContentUri[] triggerContentUris;
310     private final long triggerContentUpdateDelay;
311     private final long triggerContentMaxDelay;
312     private final boolean hasEarlyConstraint;
313     private final boolean hasLateConstraint;
314     private final NetworkRequest networkRequest;
315     private final long networkDownloadBytes;
316     private final long networkUploadBytes;
317     private final long minLatencyMillis;
318     private final long maxExecutionDelayMillis;
319     private final boolean isPeriodic;
320     private final boolean isPersisted;
321     private final long intervalMillis;
322     private final long flexMillis;
323     private final long initialBackoffMillis;
324     private final int backoffPolicy;
325     private final int priority;
326     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
327     private final int flags;
328 
329     /**
330      * Unique job id associated with this application (uid).  This is the same job ID
331      * you supplied in the {@link Builder} constructor.
332      */
getId()333     public int getId() {
334         return jobId;
335     }
336 
337     /**
338      * @see JobInfo.Builder#setExtras(PersistableBundle)
339      */
getExtras()340     public @NonNull PersistableBundle getExtras() {
341         return extras;
342     }
343 
344     /**
345      * @see JobInfo.Builder#setTransientExtras(Bundle)
346      */
getTransientExtras()347     public @NonNull Bundle getTransientExtras() {
348         return transientExtras;
349     }
350 
351     /**
352      * @see JobInfo.Builder#setClipData(ClipData, int)
353      */
getClipData()354     public @Nullable ClipData getClipData() {
355         return clipData;
356     }
357 
358     /**
359      * @see JobInfo.Builder#setClipData(ClipData, int)
360      */
getClipGrantFlags()361     public int getClipGrantFlags() {
362         return clipGrantFlags;
363     }
364 
365     /**
366      * Name of the service endpoint that will be called back into by the JobScheduler.
367      */
getService()368     public @NonNull ComponentName getService() {
369         return service;
370     }
371 
372     /** @hide */
getPriority()373     public int getPriority() {
374         return priority;
375     }
376 
377     /** @hide */
getFlags()378     public int getFlags() {
379         return flags;
380     }
381 
382     /** @hide */
isExemptedFromAppStandby()383     public boolean isExemptedFromAppStandby() {
384         return ((flags & FLAG_EXEMPT_FROM_APP_STANDBY) != 0) && !isPeriodic();
385     }
386 
387     /**
388      * @see JobInfo.Builder#setRequiresCharging(boolean)
389      */
isRequireCharging()390     public boolean isRequireCharging() {
391         return (constraintFlags & CONSTRAINT_FLAG_CHARGING) != 0;
392     }
393 
394     /**
395      * @see JobInfo.Builder#setRequiresBatteryNotLow(boolean)
396      */
isRequireBatteryNotLow()397     public boolean isRequireBatteryNotLow() {
398         return (constraintFlags & CONSTRAINT_FLAG_BATTERY_NOT_LOW) != 0;
399     }
400 
401     /**
402      * @see JobInfo.Builder#setRequiresDeviceIdle(boolean)
403      */
isRequireDeviceIdle()404     public boolean isRequireDeviceIdle() {
405         return (constraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0;
406     }
407 
408     /**
409      * @see JobInfo.Builder#setRequiresStorageNotLow(boolean)
410      */
isRequireStorageNotLow()411     public boolean isRequireStorageNotLow() {
412         return (constraintFlags & CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0;
413     }
414 
415     /**
416      * @hide
417      */
getConstraintFlags()418     public int getConstraintFlags() {
419         return constraintFlags;
420     }
421 
422     /**
423      * Which content: URIs must change for the job to be scheduled.  Returns null
424      * if there are none required.
425      * @see JobInfo.Builder#addTriggerContentUri(TriggerContentUri)
426      */
getTriggerContentUris()427     public @Nullable TriggerContentUri[] getTriggerContentUris() {
428         return triggerContentUris;
429     }
430 
431     /**
432      * When triggering on content URI changes, this is the delay from when a change
433      * is detected until the job is scheduled.
434      * @see JobInfo.Builder#setTriggerContentUpdateDelay(long)
435      */
getTriggerContentUpdateDelay()436     public long getTriggerContentUpdateDelay() {
437         return triggerContentUpdateDelay;
438     }
439 
440     /**
441      * When triggering on content URI changes, this is the maximum delay we will
442      * use before scheduling the job.
443      * @see JobInfo.Builder#setTriggerContentMaxDelay(long)
444      */
getTriggerContentMaxDelay()445     public long getTriggerContentMaxDelay() {
446         return triggerContentMaxDelay;
447     }
448 
449     /**
450      * Return the basic description of the kind of network this job requires.
451      *
452      * @deprecated This method attempts to map {@link #getRequiredNetwork()}
453      *             into the set of simple constants, which results in a loss of
454      *             fidelity. Callers should move to using
455      *             {@link #getRequiredNetwork()} directly.
456      * @see Builder#setRequiredNetworkType(int)
457      */
458     @Deprecated
getNetworkType()459     public @NetworkType int getNetworkType() {
460         if (networkRequest == null) {
461             return NETWORK_TYPE_NONE;
462         } else if (networkRequest.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
463             return NETWORK_TYPE_UNMETERED;
464         } else if (networkRequest.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING)) {
465             return NETWORK_TYPE_NOT_ROAMING;
466         } else if (networkRequest.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
467             return NETWORK_TYPE_CELLULAR;
468         } else {
469             return NETWORK_TYPE_ANY;
470         }
471     }
472 
473     /**
474      * Return the detailed description of the kind of network this job requires,
475      * or {@code null} if no specific kind of network is required.
476      *
477      * @see Builder#setRequiredNetwork(NetworkRequest)
478      */
getRequiredNetwork()479     public @Nullable NetworkRequest getRequiredNetwork() {
480         return networkRequest;
481     }
482 
483     /**
484      * @deprecated replaced by {@link #getEstimatedNetworkDownloadBytes()} and
485      *             {@link #getEstimatedNetworkUploadBytes()}.
486      * @removed
487      */
488     @Deprecated
getEstimatedNetworkBytes()489     public @BytesLong long getEstimatedNetworkBytes() {
490         if (networkDownloadBytes == NETWORK_BYTES_UNKNOWN
491                 && networkUploadBytes == NETWORK_BYTES_UNKNOWN) {
492             return NETWORK_BYTES_UNKNOWN;
493         } else if (networkDownloadBytes == NETWORK_BYTES_UNKNOWN) {
494             return networkUploadBytes;
495         } else if (networkUploadBytes == NETWORK_BYTES_UNKNOWN) {
496             return networkDownloadBytes;
497         } else {
498             return networkDownloadBytes + networkUploadBytes;
499         }
500     }
501 
502     /**
503      * Return the estimated size of download traffic that will be performed by
504      * this job, in bytes.
505      *
506      * @return Estimated size of download traffic, or
507      *         {@link #NETWORK_BYTES_UNKNOWN} when unknown.
508      * @see Builder#setEstimatedNetworkBytes(long, long)
509      */
getEstimatedNetworkDownloadBytes()510     public @BytesLong long getEstimatedNetworkDownloadBytes() {
511         return networkDownloadBytes;
512     }
513 
514     /**
515      * Return the estimated size of upload traffic that will be performed by
516      * this job, in bytes.
517      *
518      * @return Estimated size of upload traffic, or
519      *         {@link #NETWORK_BYTES_UNKNOWN} when unknown.
520      * @see Builder#setEstimatedNetworkBytes(long, long)
521      */
getEstimatedNetworkUploadBytes()522     public @BytesLong long getEstimatedNetworkUploadBytes() {
523         return networkUploadBytes;
524     }
525 
526     /**
527      * Set for a job that does not recur periodically, to specify a delay after which the job
528      * will be eligible for execution. This value is not set if the job recurs periodically.
529      * @see JobInfo.Builder#setMinimumLatency(long)
530      */
getMinLatencyMillis()531     public long getMinLatencyMillis() {
532         return minLatencyMillis;
533     }
534 
535     /**
536      * @see JobInfo.Builder#setOverrideDeadline(long)
537      */
getMaxExecutionDelayMillis()538     public long getMaxExecutionDelayMillis() {
539         return maxExecutionDelayMillis;
540     }
541 
542     /**
543      * Track whether this job will repeat with a given period.
544      * @see JobInfo.Builder#setPeriodic(long)
545      * @see JobInfo.Builder#setPeriodic(long, long)
546      */
isPeriodic()547     public boolean isPeriodic() {
548         return isPeriodic;
549     }
550 
551     /**
552      * @see JobInfo.Builder#setPersisted(boolean)
553      */
isPersisted()554     public boolean isPersisted() {
555         return isPersisted;
556     }
557 
558     /**
559      * Set to the interval between occurrences of this job. This value is <b>not</b> set if the
560      * job does not recur periodically.
561      * @see JobInfo.Builder#setPeriodic(long)
562      * @see JobInfo.Builder#setPeriodic(long, long)
563      */
getIntervalMillis()564     public long getIntervalMillis() {
565         return intervalMillis;
566     }
567 
568     /**
569      * Flex time for this job. Only valid if this is a periodic job.  The job can
570      * execute at any time in a window of flex length at the end of the period.
571      * @see JobInfo.Builder#setPeriodic(long)
572      * @see JobInfo.Builder#setPeriodic(long, long)
573      */
getFlexMillis()574     public long getFlexMillis() {
575         return flexMillis;
576     }
577 
578     /**
579      * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
580      * will be increased depending on the backoff policy specified at job creation time. Defaults
581      * to 30 seconds, minimum is currently 10 seconds.
582      * @see JobInfo.Builder#setBackoffCriteria(long, int)
583      */
getInitialBackoffMillis()584     public long getInitialBackoffMillis() {
585         return initialBackoffMillis;
586     }
587 
588     /**
589      * Return the backoff policy of this job.
590      * @see JobInfo.Builder#setBackoffCriteria(long, int)
591      */
getBackoffPolicy()592     public @BackoffPolicy int getBackoffPolicy() {
593         return backoffPolicy;
594     }
595 
596     /**
597      * @see JobInfo.Builder#setImportantWhileForeground(boolean)
598      */
isImportantWhileForeground()599     public boolean isImportantWhileForeground() {
600         return (flags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0;
601     }
602 
603     /**
604      * @see JobInfo.Builder#setPrefetch(boolean)
605      */
isPrefetch()606     public boolean isPrefetch() {
607         return (flags & FLAG_PREFETCH) != 0;
608     }
609 
610     /**
611      * User can specify an early constraint of 0L, which is valid, so we keep track of whether the
612      * function was called at all.
613      * @hide
614      */
hasEarlyConstraint()615     public boolean hasEarlyConstraint() {
616         return hasEarlyConstraint;
617     }
618 
619     /**
620      * User can specify a late constraint of 0L, which is valid, so we keep track of whether the
621      * function was called at all.
622      * @hide
623      */
hasLateConstraint()624     public boolean hasLateConstraint() {
625         return hasLateConstraint;
626     }
627 
kindofEqualsBundle(BaseBundle a, BaseBundle b)628     private static boolean kindofEqualsBundle(BaseBundle a, BaseBundle b) {
629         return (a == b) || (a != null && a.kindofEquals(b));
630     }
631 
632     @Override
equals(Object o)633     public boolean equals(Object o) {
634         if (!(o instanceof JobInfo)) {
635             return false;
636         }
637         JobInfo j = (JobInfo) o;
638         if (jobId != j.jobId) {
639             return false;
640         }
641         // XXX won't be correct if one is parcelled and the other not.
642         if (!kindofEqualsBundle(extras, j.extras)) {
643             return false;
644         }
645         // XXX won't be correct if one is parcelled and the other not.
646         if (!kindofEqualsBundle(transientExtras, j.transientExtras)) {
647             return false;
648         }
649         // XXX for now we consider two different clip data objects to be different,
650         // regardless of whether their contents are the same.
651         if (clipData != j.clipData) {
652             return false;
653         }
654         if (clipGrantFlags != j.clipGrantFlags) {
655             return false;
656         }
657         if (!Objects.equals(service, j.service)) {
658             return false;
659         }
660         if (constraintFlags != j.constraintFlags) {
661             return false;
662         }
663         if (!Arrays.equals(triggerContentUris, j.triggerContentUris)) {
664             return false;
665         }
666         if (triggerContentUpdateDelay != j.triggerContentUpdateDelay) {
667             return false;
668         }
669         if (triggerContentMaxDelay != j.triggerContentMaxDelay) {
670             return false;
671         }
672         if (hasEarlyConstraint != j.hasEarlyConstraint) {
673             return false;
674         }
675         if (hasLateConstraint != j.hasLateConstraint) {
676             return false;
677         }
678         if (!Objects.equals(networkRequest, j.networkRequest)) {
679             return false;
680         }
681         if (networkDownloadBytes != j.networkDownloadBytes) {
682             return false;
683         }
684         if (networkUploadBytes != j.networkUploadBytes) {
685             return false;
686         }
687         if (minLatencyMillis != j.minLatencyMillis) {
688             return false;
689         }
690         if (maxExecutionDelayMillis != j.maxExecutionDelayMillis) {
691             return false;
692         }
693         if (isPeriodic != j.isPeriodic) {
694             return false;
695         }
696         if (isPersisted != j.isPersisted) {
697             return false;
698         }
699         if (intervalMillis != j.intervalMillis) {
700             return false;
701         }
702         if (flexMillis != j.flexMillis) {
703             return false;
704         }
705         if (initialBackoffMillis != j.initialBackoffMillis) {
706             return false;
707         }
708         if (backoffPolicy != j.backoffPolicy) {
709             return false;
710         }
711         if (priority != j.priority) {
712             return false;
713         }
714         if (flags != j.flags) {
715             return false;
716         }
717         return true;
718     }
719 
720     @Override
hashCode()721     public int hashCode() {
722         int hashCode = jobId;
723         if (extras != null) {
724             hashCode = 31 * hashCode + extras.hashCode();
725         }
726         if (transientExtras != null) {
727             hashCode = 31 * hashCode + transientExtras.hashCode();
728         }
729         if (clipData != null) {
730             hashCode = 31 * hashCode + clipData.hashCode();
731         }
732         hashCode = 31*hashCode + clipGrantFlags;
733         if (service != null) {
734             hashCode = 31 * hashCode + service.hashCode();
735         }
736         hashCode = 31 * hashCode + constraintFlags;
737         if (triggerContentUris != null) {
738             hashCode = 31 * hashCode + Arrays.hashCode(triggerContentUris);
739         }
740         hashCode = 31 * hashCode + Long.hashCode(triggerContentUpdateDelay);
741         hashCode = 31 * hashCode + Long.hashCode(triggerContentMaxDelay);
742         hashCode = 31 * hashCode + Boolean.hashCode(hasEarlyConstraint);
743         hashCode = 31 * hashCode + Boolean.hashCode(hasLateConstraint);
744         if (networkRequest != null) {
745             hashCode = 31 * hashCode + networkRequest.hashCode();
746         }
747         hashCode = 31 * hashCode + Long.hashCode(networkDownloadBytes);
748         hashCode = 31 * hashCode + Long.hashCode(networkUploadBytes);
749         hashCode = 31 * hashCode + Long.hashCode(minLatencyMillis);
750         hashCode = 31 * hashCode + Long.hashCode(maxExecutionDelayMillis);
751         hashCode = 31 * hashCode + Boolean.hashCode(isPeriodic);
752         hashCode = 31 * hashCode + Boolean.hashCode(isPersisted);
753         hashCode = 31 * hashCode + Long.hashCode(intervalMillis);
754         hashCode = 31 * hashCode + Long.hashCode(flexMillis);
755         hashCode = 31 * hashCode + Long.hashCode(initialBackoffMillis);
756         hashCode = 31 * hashCode + backoffPolicy;
757         hashCode = 31 * hashCode + priority;
758         hashCode = 31 * hashCode + flags;
759         return hashCode;
760     }
761 
JobInfo(Parcel in)762     private JobInfo(Parcel in) {
763         jobId = in.readInt();
764         extras = in.readPersistableBundle();
765         transientExtras = in.readBundle();
766         if (in.readInt() != 0) {
767             clipData = ClipData.CREATOR.createFromParcel(in);
768             clipGrantFlags = in.readInt();
769         } else {
770             clipData = null;
771             clipGrantFlags = 0;
772         }
773         service = in.readParcelable(null);
774         constraintFlags = in.readInt();
775         triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR);
776         triggerContentUpdateDelay = in.readLong();
777         triggerContentMaxDelay = in.readLong();
778         if (in.readInt() != 0) {
779             networkRequest = NetworkRequest.CREATOR.createFromParcel(in);
780         } else {
781             networkRequest = null;
782         }
783         networkDownloadBytes = in.readLong();
784         networkUploadBytes = in.readLong();
785         minLatencyMillis = in.readLong();
786         maxExecutionDelayMillis = in.readLong();
787         isPeriodic = in.readInt() == 1;
788         isPersisted = in.readInt() == 1;
789         intervalMillis = in.readLong();
790         flexMillis = in.readLong();
791         initialBackoffMillis = in.readLong();
792         backoffPolicy = in.readInt();
793         hasEarlyConstraint = in.readInt() == 1;
794         hasLateConstraint = in.readInt() == 1;
795         priority = in.readInt();
796         flags = in.readInt();
797     }
798 
JobInfo(JobInfo.Builder b)799     private JobInfo(JobInfo.Builder b) {
800         jobId = b.mJobId;
801         extras = b.mExtras.deepCopy();
802         transientExtras = b.mTransientExtras.deepCopy();
803         clipData = b.mClipData;
804         clipGrantFlags = b.mClipGrantFlags;
805         service = b.mJobService;
806         constraintFlags = b.mConstraintFlags;
807         triggerContentUris = b.mTriggerContentUris != null
808                 ? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()])
809                 : null;
810         triggerContentUpdateDelay = b.mTriggerContentUpdateDelay;
811         triggerContentMaxDelay = b.mTriggerContentMaxDelay;
812         networkRequest = b.mNetworkRequest;
813         networkDownloadBytes = b.mNetworkDownloadBytes;
814         networkUploadBytes = b.mNetworkUploadBytes;
815         minLatencyMillis = b.mMinLatencyMillis;
816         maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
817         isPeriodic = b.mIsPeriodic;
818         isPersisted = b.mIsPersisted;
819         intervalMillis = b.mIntervalMillis;
820         flexMillis = b.mFlexMillis;
821         initialBackoffMillis = b.mInitialBackoffMillis;
822         backoffPolicy = b.mBackoffPolicy;
823         hasEarlyConstraint = b.mHasEarlyConstraint;
824         hasLateConstraint = b.mHasLateConstraint;
825         priority = b.mPriority;
826         flags = b.mFlags;
827     }
828 
829     @Override
describeContents()830     public int describeContents() {
831         return 0;
832     }
833 
834     @Override
writeToParcel(Parcel out, int flags)835     public void writeToParcel(Parcel out, int flags) {
836         out.writeInt(jobId);
837         out.writePersistableBundle(extras);
838         out.writeBundle(transientExtras);
839         if (clipData != null) {
840             out.writeInt(1);
841             clipData.writeToParcel(out, flags);
842             out.writeInt(clipGrantFlags);
843         } else {
844             out.writeInt(0);
845         }
846         out.writeParcelable(service, flags);
847         out.writeInt(constraintFlags);
848         out.writeTypedArray(triggerContentUris, flags);
849         out.writeLong(triggerContentUpdateDelay);
850         out.writeLong(triggerContentMaxDelay);
851         if (networkRequest != null) {
852             out.writeInt(1);
853             networkRequest.writeToParcel(out, flags);
854         } else {
855             out.writeInt(0);
856         }
857         out.writeLong(networkDownloadBytes);
858         out.writeLong(networkUploadBytes);
859         out.writeLong(minLatencyMillis);
860         out.writeLong(maxExecutionDelayMillis);
861         out.writeInt(isPeriodic ? 1 : 0);
862         out.writeInt(isPersisted ? 1 : 0);
863         out.writeLong(intervalMillis);
864         out.writeLong(flexMillis);
865         out.writeLong(initialBackoffMillis);
866         out.writeInt(backoffPolicy);
867         out.writeInt(hasEarlyConstraint ? 1 : 0);
868         out.writeInt(hasLateConstraint ? 1 : 0);
869         out.writeInt(priority);
870         out.writeInt(this.flags);
871     }
872 
873     public static final @android.annotation.NonNull Creator<JobInfo> CREATOR = new Creator<JobInfo>() {
874         @Override
875         public JobInfo createFromParcel(Parcel in) {
876             return new JobInfo(in);
877         }
878 
879         @Override
880         public JobInfo[] newArray(int size) {
881             return new JobInfo[size];
882         }
883     };
884 
885     @Override
toString()886     public String toString() {
887         return "(job:" + jobId + "/" + service.flattenToShortString() + ")";
888     }
889 
890     /**
891      * Information about a content URI modification that a job would like to
892      * trigger on.
893      */
894     public static final class TriggerContentUri implements Parcelable {
895         private final Uri mUri;
896         private final int mFlags;
897 
898         /** @hide */
899         @Retention(RetentionPolicy.SOURCE)
900         @IntDef(flag = true, prefix = { "FLAG_" }, value = {
901                 FLAG_NOTIFY_FOR_DESCENDANTS,
902         })
903         public @interface Flags { }
904 
905         /**
906          * Flag for trigger: also trigger if any descendants of the given URI change.
907          * Corresponds to the <var>notifyForDescendants</var> of
908          * {@link android.content.ContentResolver#registerContentObserver}.
909          */
910         public static final int FLAG_NOTIFY_FOR_DESCENDANTS = 1<<0;
911 
912         /**
913          * Create a new trigger description.
914          * @param uri The URI to observe.  Must be non-null.
915          * @param flags Flags for the observer.
916          */
TriggerContentUri(@onNull Uri uri, @Flags int flags)917         public TriggerContentUri(@NonNull Uri uri, @Flags int flags) {
918             mUri = uri;
919             mFlags = flags;
920         }
921 
922         /**
923          * Return the Uri this trigger was created for.
924          */
getUri()925         public Uri getUri() {
926             return mUri;
927         }
928 
929         /**
930          * Return the flags supplied for the trigger.
931          */
getFlags()932         public @Flags int getFlags() {
933             return mFlags;
934         }
935 
936         @Override
equals(Object o)937         public boolean equals(Object o) {
938             if (!(o instanceof TriggerContentUri)) {
939                 return false;
940             }
941             TriggerContentUri t = (TriggerContentUri) o;
942             return Objects.equals(t.mUri, mUri) && t.mFlags == mFlags;
943         }
944 
945         @Override
hashCode()946         public int hashCode() {
947             return (mUri == null ? 0 : mUri.hashCode()) ^ mFlags;
948         }
949 
TriggerContentUri(Parcel in)950         private TriggerContentUri(Parcel in) {
951             mUri = Uri.CREATOR.createFromParcel(in);
952             mFlags = in.readInt();
953         }
954 
955         @Override
describeContents()956         public int describeContents() {
957             return 0;
958         }
959 
960         @Override
writeToParcel(Parcel out, int flags)961         public void writeToParcel(Parcel out, int flags) {
962             mUri.writeToParcel(out, flags);
963             out.writeInt(mFlags);
964         }
965 
966         public static final @android.annotation.NonNull Creator<TriggerContentUri> CREATOR = new Creator<TriggerContentUri>() {
967             @Override
968             public TriggerContentUri createFromParcel(Parcel in) {
969                 return new TriggerContentUri(in);
970             }
971 
972             @Override
973             public TriggerContentUri[] newArray(int size) {
974                 return new TriggerContentUri[size];
975             }
976         };
977     }
978 
979     /** Builder class for constructing {@link JobInfo} objects. */
980     public static final class Builder {
981         private final int mJobId;
982         private final ComponentName mJobService;
983         private PersistableBundle mExtras = PersistableBundle.EMPTY;
984         private Bundle mTransientExtras = Bundle.EMPTY;
985         private ClipData mClipData;
986         private int mClipGrantFlags;
987         private int mPriority = PRIORITY_DEFAULT;
988         private int mFlags;
989         // Requirements.
990         private int mConstraintFlags;
991         private NetworkRequest mNetworkRequest;
992         private long mNetworkDownloadBytes = NETWORK_BYTES_UNKNOWN;
993         private long mNetworkUploadBytes = NETWORK_BYTES_UNKNOWN;
994         private ArrayList<TriggerContentUri> mTriggerContentUris;
995         private long mTriggerContentUpdateDelay = -1;
996         private long mTriggerContentMaxDelay = -1;
997         private boolean mIsPersisted;
998         // One-off parameters.
999         private long mMinLatencyMillis;
1000         private long mMaxExecutionDelayMillis;
1001         // Periodic parameters.
1002         private boolean mIsPeriodic;
1003         private boolean mHasEarlyConstraint;
1004         private boolean mHasLateConstraint;
1005         private long mIntervalMillis;
1006         private long mFlexMillis;
1007         // Back-off parameters.
1008         private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS;
1009         private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY;
1010         /** Easy way to track whether the client has tried to set a back-off policy. */
1011         private boolean mBackoffPolicySet = false;
1012 
1013         /**
1014          * Initialize a new Builder to construct a {@link JobInfo}.
1015          *
1016          * @param jobId Application-provided id for this job. Subsequent calls to cancel, or
1017          * jobs created with the same jobId, will update the pre-existing job with
1018          * the same id.  This ID must be unique across all clients of the same uid
1019          * (not just the same package).  You will want to make sure this is a stable
1020          * id across app updates, so probably not based on a resource ID.
1021          * @param jobService The endpoint that you implement that will receive the callback from the
1022          * JobScheduler.
1023          */
Builder(int jobId, @NonNull ComponentName jobService)1024         public Builder(int jobId, @NonNull ComponentName jobService) {
1025             mJobService = jobService;
1026             mJobId = jobId;
1027         }
1028 
1029         /** @hide */
1030         @UnsupportedAppUsage
setPriority(int priority)1031         public Builder setPriority(int priority) {
1032             mPriority = priority;
1033             return this;
1034         }
1035 
1036         /** @hide */
1037         @UnsupportedAppUsage
setFlags(int flags)1038         public Builder setFlags(int flags) {
1039             mFlags = flags;
1040             return this;
1041         }
1042 
1043         /**
1044          * Set optional extras. This is persisted, so we only allow primitive types.
1045          * @param extras Bundle containing extras you want the scheduler to hold on to for you.
1046          * @see JobInfo#getExtras()
1047          */
setExtras(@onNull PersistableBundle extras)1048         public Builder setExtras(@NonNull PersistableBundle extras) {
1049             mExtras = extras;
1050             return this;
1051         }
1052 
1053         /**
1054          * Set optional transient extras.
1055          *
1056          * <p>Because setting this property is not compatible with persisted
1057          * jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
1058          * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
1059          *
1060          * @param extras Bundle containing extras you want the scheduler to hold on to for you.
1061          * @see JobInfo#getTransientExtras()
1062          */
setTransientExtras(@onNull Bundle extras)1063         public Builder setTransientExtras(@NonNull Bundle extras) {
1064             mTransientExtras = extras;
1065             return this;
1066         }
1067 
1068         /**
1069          * Set a {@link ClipData} associated with this Job.
1070          *
1071          * <p>The main purpose of providing a ClipData is to allow granting of
1072          * URI permissions for data associated with the clip.  The exact kind
1073          * of permission grant to perform is specified through <var>grantFlags</var>.
1074          *
1075          * <p>If the ClipData contains items that are Intents, any
1076          * grant flags in those Intents will be ignored.  Only flags provided as an argument
1077          * to this method are respected, and will be applied to all Uri or
1078          * Intent items in the clip (or sub-items of the clip).
1079          *
1080          * <p>Because setting this property is not compatible with persisted
1081          * jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
1082          * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
1083          *
1084          * @param clip The new clip to set.  May be null to clear the current clip.
1085          * @param grantFlags The desired permissions to grant for any URIs.  This should be
1086          * a combination of {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION},
1087          * {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, and
1088          * {@link android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION}.
1089          * @see JobInfo#getClipData()
1090          * @see JobInfo#getClipGrantFlags()
1091          */
setClipData(@ullable ClipData clip, int grantFlags)1092         public Builder setClipData(@Nullable ClipData clip, int grantFlags) {
1093             mClipData = clip;
1094             mClipGrantFlags = grantFlags;
1095             return this;
1096         }
1097 
1098         /**
1099          * Set basic description of the kind of network your job requires. If
1100          * you need more precise control over network capabilities, see
1101          * {@link #setRequiredNetwork(NetworkRequest)}.
1102          * <p>
1103          * If your job doesn't need a network connection, you don't need to call
1104          * this method, as the default value is {@link #NETWORK_TYPE_NONE}.
1105          * <p>
1106          * Calling this method defines network as a strict requirement for your
1107          * job. If the network requested is not available your job will never
1108          * run. See {@link #setOverrideDeadline(long)} to change this behavior.
1109          * Calling this method will override any requirements previously defined
1110          * by {@link #setRequiredNetwork(NetworkRequest)}; you typically only
1111          * want to call one of these methods.
1112          * <p class="note">
1113          * When your job executes in
1114          * {@link JobService#onStartJob(JobParameters)}, be sure to use the
1115          * specific network returned by {@link JobParameters#getNetwork()},
1116          * otherwise you'll use the default network which may not meet this
1117          * constraint.
1118          *
1119          * @see #setRequiredNetwork(NetworkRequest)
1120          * @see JobInfo#getNetworkType()
1121          * @see JobParameters#getNetwork()
1122          */
setRequiredNetworkType(@etworkType int networkType)1123         public Builder setRequiredNetworkType(@NetworkType int networkType) {
1124             if (networkType == NETWORK_TYPE_NONE) {
1125                 return setRequiredNetwork(null);
1126             } else {
1127                 final NetworkRequest.Builder builder = new NetworkRequest.Builder();
1128 
1129                 // All types require validated Internet
1130                 builder.addCapability(NET_CAPABILITY_INTERNET);
1131                 builder.addCapability(NET_CAPABILITY_VALIDATED);
1132                 builder.removeCapability(NET_CAPABILITY_NOT_VPN);
1133 
1134                 if (networkType == NETWORK_TYPE_ANY) {
1135                     // No other capabilities
1136                 } else if (networkType == NETWORK_TYPE_UNMETERED) {
1137                     builder.addCapability(NET_CAPABILITY_NOT_METERED);
1138                 } else if (networkType == NETWORK_TYPE_NOT_ROAMING) {
1139                     builder.addCapability(NET_CAPABILITY_NOT_ROAMING);
1140                 } else if (networkType == NETWORK_TYPE_CELLULAR) {
1141                     builder.addTransportType(TRANSPORT_CELLULAR);
1142                 }
1143 
1144                 return setRequiredNetwork(builder.build());
1145             }
1146         }
1147 
1148         /**
1149          * Set detailed description of the kind of network your job requires.
1150          * <p>
1151          * If your job doesn't need a network connection, you don't need to call
1152          * this method, as the default is {@code null}.
1153          * <p>
1154          * Calling this method defines network as a strict requirement for your
1155          * job. If the network requested is not available your job will never
1156          * run. See {@link #setOverrideDeadline(long)} to change this behavior.
1157          * Calling this method will override any requirements previously defined
1158          * by {@link #setRequiredNetworkType(int)}; you typically only want to
1159          * call one of these methods.
1160          * <p class="note">
1161          * When your job executes in
1162          * {@link JobService#onStartJob(JobParameters)}, be sure to use the
1163          * specific network returned by {@link JobParameters#getNetwork()},
1164          * otherwise you'll use the default network which may not meet this
1165          * constraint.
1166          *
1167          * @param networkRequest The detailed description of the kind of network
1168          *            this job requires, or {@code null} if no specific kind of
1169          *            network is required. Defining a {@link NetworkSpecifier}
1170          *            is only supported for jobs that aren't persisted.
1171          * @see #setRequiredNetworkType(int)
1172          * @see JobInfo#getRequiredNetwork()
1173          * @see JobParameters#getNetwork()
1174          */
setRequiredNetwork(@ullable NetworkRequest networkRequest)1175         public Builder setRequiredNetwork(@Nullable NetworkRequest networkRequest) {
1176             mNetworkRequest = networkRequest;
1177             return this;
1178         }
1179 
1180         /**
1181          * @deprecated replaced by
1182          *             {@link #setEstimatedNetworkBytes(long, long)}.
1183          * @removed
1184          */
1185         @Deprecated
setEstimatedNetworkBytes(@ytesLong long networkBytes)1186         public Builder setEstimatedNetworkBytes(@BytesLong long networkBytes) {
1187             return setEstimatedNetworkBytes(networkBytes, NETWORK_BYTES_UNKNOWN);
1188         }
1189 
1190         /**
1191          * Set the estimated size of network traffic that will be performed by
1192          * this job, in bytes.
1193          * <p>
1194          * Apps are encouraged to provide values that are as accurate as
1195          * possible, but when the exact size isn't available, an
1196          * order-of-magnitude estimate can be provided instead. Here are some
1197          * specific examples:
1198          * <ul>
1199          * <li>A job that is backing up a photo knows the exact size of that
1200          * photo, so it should provide that size as the estimate.
1201          * <li>A job that refreshes top news stories wouldn't know an exact
1202          * size, but if the size is expected to be consistently around 100KB, it
1203          * can provide that order-of-magnitude value as the estimate.
1204          * <li>A job that synchronizes email could end up using an extreme range
1205          * of data, from under 1KB when nothing has changed, to dozens of MB
1206          * when there are new emails with attachments. Jobs that cannot provide
1207          * reasonable estimates should use the sentinel value
1208          * {@link JobInfo#NETWORK_BYTES_UNKNOWN}.
1209          * </ul>
1210          * Note that the system may choose to delay jobs with large network
1211          * usage estimates when the device has a poor network connection, in
1212          * order to save battery.
1213          * <p>
1214          * The values provided here only reflect the traffic that will be
1215          * performed by the base job; if you're using {@link JobWorkItem} then
1216          * you also need to define the network traffic used by each work item
1217          * when constructing them.
1218          *
1219          * @param downloadBytes The estimated size of network traffic that will
1220          *            be downloaded by this job, in bytes.
1221          * @param uploadBytes The estimated size of network traffic that will be
1222          *            uploaded by this job, in bytes.
1223          * @see JobInfo#getEstimatedNetworkDownloadBytes()
1224          * @see JobInfo#getEstimatedNetworkUploadBytes()
1225          * @see JobWorkItem#JobWorkItem(android.content.Intent, long, long)
1226          */
setEstimatedNetworkBytes(@ytesLong long downloadBytes, @BytesLong long uploadBytes)1227         public Builder setEstimatedNetworkBytes(@BytesLong long downloadBytes,
1228                 @BytesLong long uploadBytes) {
1229             mNetworkDownloadBytes = downloadBytes;
1230             mNetworkUploadBytes = uploadBytes;
1231             return this;
1232         }
1233 
1234         /**
1235          * Specify that to run this job, the device must be charging (or be a
1236          * non-battery-powered device connected to permanent power, such as Android TV
1237          * devices). This defaults to {@code false}.
1238          *
1239          * <p class="note">For purposes of running jobs, a battery-powered device
1240          * "charging" is not quite the same as simply being connected to power.  If the
1241          * device is so busy that the battery is draining despite a power connection, jobs
1242          * with this constraint will <em>not</em> run.  This can happen during some
1243          * common use cases such as video chat, particularly if the device is plugged in
1244          * to USB rather than to wall power.
1245          *
1246          * @param requiresCharging Pass {@code true} to require that the device be
1247          *     charging in order to run the job.
1248          * @see JobInfo#isRequireCharging()
1249          */
setRequiresCharging(boolean requiresCharging)1250         public Builder setRequiresCharging(boolean requiresCharging) {
1251             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_CHARGING)
1252                     | (requiresCharging ? CONSTRAINT_FLAG_CHARGING : 0);
1253             return this;
1254         }
1255 
1256         /**
1257          * Specify that to run this job, the device's battery level must not be low.
1258          * This defaults to false.  If true, the job will only run when the battery level
1259          * is not low, which is generally the point where the user is given a "low battery"
1260          * warning.
1261          * @param batteryNotLow Whether or not the device's battery level must not be low.
1262          * @see JobInfo#isRequireBatteryNotLow()
1263          */
setRequiresBatteryNotLow(boolean batteryNotLow)1264         public Builder setRequiresBatteryNotLow(boolean batteryNotLow) {
1265             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_BATTERY_NOT_LOW)
1266                     | (batteryNotLow ? CONSTRAINT_FLAG_BATTERY_NOT_LOW : 0);
1267             return this;
1268         }
1269 
1270         /**
1271          * When set {@code true}, ensure that this job will not run if the device is in active use.
1272          * The default state is {@code false}: that is, the for the job to be runnable even when
1273          * someone is interacting with the device.
1274          *
1275          * <p>This state is a loose definition provided by the system. In general, it means that
1276          * the device is not currently being used interactively, and has not been in use for some
1277          * time. As such, it is a good time to perform resource heavy jobs. Bear in mind that
1278          * battery usage will still be attributed to your application, and surfaced to the user in
1279          * battery stats.</p>
1280          *
1281          * <p class="note">Despite the similar naming, this job constraint is <em>not</em>
1282          * related to the system's "device idle" or "doze" states.  This constraint only
1283          * determines whether a job is allowed to run while the device is directly in use.
1284          *
1285          * @param requiresDeviceIdle Pass {@code true} to prevent the job from running
1286          *     while the device is being used interactively.
1287          * @see JobInfo#isRequireDeviceIdle()
1288          */
setRequiresDeviceIdle(boolean requiresDeviceIdle)1289         public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
1290             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_DEVICE_IDLE)
1291                     | (requiresDeviceIdle ? CONSTRAINT_FLAG_DEVICE_IDLE : 0);
1292             return this;
1293         }
1294 
1295         /**
1296          * Specify that to run this job, the device's available storage must not be low.
1297          * This defaults to false.  If true, the job will only run when the device is not
1298          * in a low storage state, which is generally the point where the user is given a
1299          * "low storage" warning.
1300          * @param storageNotLow Whether or not the device's available storage must not be low.
1301          * @see JobInfo#isRequireStorageNotLow()
1302          */
setRequiresStorageNotLow(boolean storageNotLow)1303         public Builder setRequiresStorageNotLow(boolean storageNotLow) {
1304             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_STORAGE_NOT_LOW)
1305                     | (storageNotLow ? CONSTRAINT_FLAG_STORAGE_NOT_LOW : 0);
1306             return this;
1307         }
1308 
1309         /**
1310          * Add a new content: URI that will be monitored with a
1311          * {@link android.database.ContentObserver}, and will cause the job to execute if changed.
1312          * If you have any trigger content URIs associated with a job, it will not execute until
1313          * there has been a change report for one or more of them.
1314          *
1315          * <p>Note that trigger URIs can not be used in combination with
1316          * {@link #setPeriodic(long)} or {@link #setPersisted(boolean)}.  To continually monitor
1317          * for content changes, you need to schedule a new JobInfo observing the same URIs
1318          * before you finish execution of the JobService handling the most recent changes.
1319          * Following this pattern will ensure you do not lost any content changes: while your
1320          * job is running, the system will continue monitoring for content changes, and propagate
1321          * any it sees over to the next job you schedule.</p>
1322          *
1323          * <p>Because setting this property is not compatible with periodic or
1324          * persisted jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
1325          * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
1326          *
1327          * <p>The following example shows how this feature can be used to monitor for changes
1328          * in the photos on a device.</p>
1329          *
1330          * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/PhotosContentJob.java
1331          *      job}
1332          *
1333          * @param uri The content: URI to monitor.
1334          * @see JobInfo#getTriggerContentUris()
1335          */
addTriggerContentUri(@onNull TriggerContentUri uri)1336         public Builder addTriggerContentUri(@NonNull TriggerContentUri uri) {
1337             if (mTriggerContentUris == null) {
1338                 mTriggerContentUris = new ArrayList<>();
1339             }
1340             mTriggerContentUris.add(uri);
1341             return this;
1342         }
1343 
1344         /**
1345          * Set the delay (in milliseconds) from when a content change is detected until
1346          * the job is scheduled.  If there are more changes during that time, the delay
1347          * will be reset to start at the time of the most recent change.
1348          * @param durationMs Delay after most recent content change, in milliseconds.
1349          * @see JobInfo#getTriggerContentUpdateDelay()
1350          */
setTriggerContentUpdateDelay(long durationMs)1351         public Builder setTriggerContentUpdateDelay(long durationMs) {
1352             mTriggerContentUpdateDelay = durationMs;
1353             return this;
1354         }
1355 
1356         /**
1357          * Set the maximum total delay (in milliseconds) that is allowed from the first
1358          * time a content change is detected until the job is scheduled.
1359          * @param durationMs Delay after initial content change, in milliseconds.
1360          * @see JobInfo#getTriggerContentMaxDelay()
1361          */
setTriggerContentMaxDelay(long durationMs)1362         public Builder setTriggerContentMaxDelay(long durationMs) {
1363             mTriggerContentMaxDelay = durationMs;
1364             return this;
1365         }
1366 
1367         /**
1368          * Specify that this job should recur with the provided interval, not more than once per
1369          * period. You have no control over when within this interval this job will be executed,
1370          * only the guarantee that it will be executed at most once within this interval.
1371          * Setting this function on the builder with {@link #setMinimumLatency(long)} or
1372          * {@link #setOverrideDeadline(long)} will result in an error.
1373          * @param intervalMillis Millisecond interval for which this job will repeat.
1374          * @see JobInfo#getIntervalMillis()
1375          * @see JobInfo#getFlexMillis()
1376          */
setPeriodic(long intervalMillis)1377         public Builder setPeriodic(long intervalMillis) {
1378             return setPeriodic(intervalMillis, intervalMillis);
1379         }
1380 
1381         /**
1382          * Specify that this job should recur with the provided interval and flex. The job can
1383          * execute at any time in a window of flex length at the end of the period.
1384          * @param intervalMillis Millisecond interval for which this job will repeat. A minimum
1385          *                       value of {@link #getMinPeriodMillis()} is enforced.
1386          * @param flexMillis Millisecond flex for this job. Flex is clamped to be at least
1387          *                   {@link #getMinFlexMillis()} or 5 percent of the period, whichever is
1388          *                   higher.
1389          * @see JobInfo#getIntervalMillis()
1390          * @see JobInfo#getFlexMillis()
1391          */
setPeriodic(long intervalMillis, long flexMillis)1392         public Builder setPeriodic(long intervalMillis, long flexMillis) {
1393             final long minPeriod = getMinPeriodMillis();
1394             if (intervalMillis < minPeriod) {
1395                 Log.w(TAG, "Requested interval " + formatDuration(intervalMillis) + " for job "
1396                         + mJobId + " is too small; raising to " + formatDuration(minPeriod));
1397                 intervalMillis = minPeriod;
1398             }
1399 
1400             final long percentClamp = 5 * intervalMillis / 100;
1401             final long minFlex = Math.max(percentClamp, getMinFlexMillis());
1402             if (flexMillis < minFlex) {
1403                 Log.w(TAG, "Requested flex " + formatDuration(flexMillis) + " for job " + mJobId
1404                         + " is too small; raising to " + formatDuration(minFlex));
1405                 flexMillis = minFlex;
1406             }
1407 
1408             mIsPeriodic = true;
1409             mIntervalMillis = intervalMillis;
1410             mFlexMillis = flexMillis;
1411             mHasEarlyConstraint = mHasLateConstraint = true;
1412             return this;
1413         }
1414 
1415         /**
1416          * Specify that this job should be delayed by the provided amount of time.
1417          * Because it doesn't make sense setting this property on a periodic job, doing so will
1418          * throw an {@link java.lang.IllegalArgumentException} when
1419          * {@link android.app.job.JobInfo.Builder#build()} is called.
1420          * @param minLatencyMillis Milliseconds before which this job will not be considered for
1421          *                         execution.
1422          * @see JobInfo#getMinLatencyMillis()
1423          */
setMinimumLatency(long minLatencyMillis)1424         public Builder setMinimumLatency(long minLatencyMillis) {
1425             mMinLatencyMillis = minLatencyMillis;
1426             mHasEarlyConstraint = true;
1427             return this;
1428         }
1429 
1430         /**
1431          * Set deadline which is the maximum scheduling latency. The job will be run by this
1432          * deadline even if other requirements are not met. Because it doesn't make sense setting
1433          * this property on a periodic job, doing so will throw an
1434          * {@link java.lang.IllegalArgumentException} when
1435          * {@link android.app.job.JobInfo.Builder#build()} is called.
1436          * @see JobInfo#getMaxExecutionDelayMillis()
1437          */
setOverrideDeadline(long maxExecutionDelayMillis)1438         public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
1439             mMaxExecutionDelayMillis = maxExecutionDelayMillis;
1440             mHasLateConstraint = true;
1441             return this;
1442         }
1443 
1444         /**
1445          * Set up the back-off/retry policy.
1446          * This defaults to some respectable values: {30 seconds, Exponential}. We cap back-off at
1447          * 5hrs.
1448          * Note that trying to set a backoff criteria for a job with
1449          * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
1450          * This is because back-off typically does not make sense for these types of jobs. See
1451          * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
1452          * for more description of the return value for the case of a job executing while in idle
1453          * mode.
1454          * @param initialBackoffMillis Millisecond time interval to wait initially when job has
1455          *                             failed.
1456          * @see JobInfo#getInitialBackoffMillis()
1457          * @see JobInfo#getBackoffPolicy()
1458          */
setBackoffCriteria(long initialBackoffMillis, @BackoffPolicy int backoffPolicy)1459         public Builder setBackoffCriteria(long initialBackoffMillis,
1460                 @BackoffPolicy int backoffPolicy) {
1461             final long minBackoff = getMinBackoffMillis();
1462             if (initialBackoffMillis < minBackoff) {
1463                 Log.w(TAG, "Requested backoff " + formatDuration(initialBackoffMillis) + " for job "
1464                         + mJobId + " is too small; raising to " + formatDuration(minBackoff));
1465                 initialBackoffMillis = minBackoff;
1466             }
1467 
1468             mBackoffPolicySet = true;
1469             mInitialBackoffMillis = initialBackoffMillis;
1470             mBackoffPolicy = backoffPolicy;
1471             return this;
1472         }
1473 
1474         /**
1475          * Setting this to true indicates that this job is important while the scheduling app
1476          * is in the foreground or on the temporary whitelist for background restrictions.
1477          * This means that the system will relax doze restrictions on this job during this time.
1478          *
1479          * Apps should use this flag only for short jobs that are essential for the app to function
1480          * properly in the foreground.
1481          *
1482          * Note that once the scheduling app is no longer whitelisted from background restrictions
1483          * and in the background, or the job failed due to unsatisfied constraints,
1484          * this job should be expected to behave like other jobs without this flag.
1485          *
1486          * @param importantWhileForeground whether to relax doze restrictions for this job when the
1487          *                                 app is in the foreground. False by default.
1488          * @see JobInfo#isImportantWhileForeground()
1489          */
setImportantWhileForeground(boolean importantWhileForeground)1490         public Builder setImportantWhileForeground(boolean importantWhileForeground) {
1491             if (importantWhileForeground) {
1492                 mFlags |= FLAG_IMPORTANT_WHILE_FOREGROUND;
1493             } else {
1494                 mFlags &= (~FLAG_IMPORTANT_WHILE_FOREGROUND);
1495             }
1496             return this;
1497         }
1498 
1499         /**
1500          * @removed
1501          * @deprecated replaced with {@link #setPrefetch(boolean)}
1502          */
1503         @Deprecated
setIsPrefetch(boolean isPrefetch)1504         public Builder setIsPrefetch(boolean isPrefetch) {
1505             return setPrefetch(isPrefetch);
1506         }
1507 
1508         /**
1509          * Setting this to true indicates that this job is designed to prefetch
1510          * content that will make a material improvement to the experience of
1511          * the specific user of this device. For example, fetching top headlines
1512          * of interest to the current user.
1513          * <p>
1514          * The system may use this signal to relax the network constraints you
1515          * originally requested, such as allowing a
1516          * {@link JobInfo#NETWORK_TYPE_UNMETERED} job to run over a metered
1517          * network when there is a surplus of metered data available. The system
1518          * may also use this signal in combination with end user usage patterns
1519          * to ensure data is prefetched before the user launches your app.
1520          * @see JobInfo#isPrefetch()
1521          */
setPrefetch(boolean prefetch)1522         public Builder setPrefetch(boolean prefetch) {
1523             if (prefetch) {
1524                 mFlags |= FLAG_PREFETCH;
1525             } else {
1526                 mFlags &= (~FLAG_PREFETCH);
1527             }
1528             return this;
1529         }
1530 
1531         /**
1532          * Set whether or not to persist this job across device reboots.
1533          *
1534          * @param isPersisted True to indicate that the job will be written to
1535          *            disk and loaded at boot.
1536          * @see JobInfo#isPersisted()
1537          */
1538         @RequiresPermission(android.Manifest.permission.RECEIVE_BOOT_COMPLETED)
setPersisted(boolean isPersisted)1539         public Builder setPersisted(boolean isPersisted) {
1540             mIsPersisted = isPersisted;
1541             return this;
1542         }
1543 
1544         /**
1545          * @return The job object to hand to the JobScheduler. This object is immutable.
1546          */
build()1547         public JobInfo build() {
1548             // Check that network estimates require network type
1549             if ((mNetworkDownloadBytes > 0 || mNetworkUploadBytes > 0) && mNetworkRequest == null) {
1550                 throw new IllegalArgumentException(
1551                         "Can't provide estimated network usage without requiring a network");
1552             }
1553             // We can't serialize network specifiers
1554             if (mIsPersisted && mNetworkRequest != null
1555                     && mNetworkRequest.networkCapabilities.getNetworkSpecifier() != null) {
1556                 throw new IllegalArgumentException(
1557                         "Network specifiers aren't supported for persistent jobs");
1558             }
1559             // Check that a deadline was not set on a periodic job.
1560             if (mIsPeriodic) {
1561                 if (mMaxExecutionDelayMillis != 0L) {
1562                     throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
1563                             "periodic job.");
1564                 }
1565                 if (mMinLatencyMillis != 0L) {
1566                     throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
1567                             "periodic job");
1568                 }
1569                 if (mTriggerContentUris != null) {
1570                     throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +
1571                             "periodic job");
1572                 }
1573             }
1574             if (mIsPersisted) {
1575                 if (mTriggerContentUris != null) {
1576                     throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +
1577                             "persisted job");
1578                 }
1579                 if (!mTransientExtras.isEmpty()) {
1580                     throw new IllegalArgumentException("Can't call setTransientExtras() on a " +
1581                             "persisted job");
1582                 }
1583                 if (mClipData != null) {
1584                     throw new IllegalArgumentException("Can't call setClipData() on a " +
1585                             "persisted job");
1586                 }
1587             }
1588             if ((mFlags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0 && mHasEarlyConstraint) {
1589                 throw new IllegalArgumentException("An important while foreground job cannot "
1590                         + "have a time delay");
1591             }
1592             if (mBackoffPolicySet && (mConstraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0) {
1593                 throw new IllegalArgumentException("An idle mode job will not respect any" +
1594                         " back-off policy, so calling setBackoffCriteria with" +
1595                         " setRequiresDeviceIdle is an error.");
1596             }
1597             return new JobInfo(this);
1598         }
1599 
1600         /**
1601          * @hide
1602          */
summarize()1603         public String summarize() {
1604             final String service = (mJobService != null)
1605                     ? mJobService.flattenToShortString()
1606                     : "null";
1607             return "JobInfo.Builder{job:" + mJobId + "/" + service + "}";
1608         }
1609     }
1610 
1611     /**
1612      * Convert a priority integer into a human readable string for debugging.
1613      * @hide
1614      */
getPriorityString(int priority)1615     public static String getPriorityString(int priority) {
1616         switch (priority) {
1617             case PRIORITY_DEFAULT:
1618                 return PRIORITY_DEFAULT + " [DEFAULT]";
1619             case PRIORITY_SYNC_EXPEDITED:
1620                 return PRIORITY_SYNC_EXPEDITED + " [SYNC_EXPEDITED]";
1621             case PRIORITY_SYNC_INITIALIZATION:
1622                 return PRIORITY_SYNC_INITIALIZATION + " [SYNC_INITIALIZATION]";
1623             case PRIORITY_BOUND_FOREGROUND_SERVICE:
1624                 return PRIORITY_BOUND_FOREGROUND_SERVICE + " [BFGS_APP]";
1625             case PRIORITY_FOREGROUND_SERVICE:
1626                 return PRIORITY_FOREGROUND_SERVICE + " [FGS_APP]";
1627             case PRIORITY_TOP_APP:
1628                 return PRIORITY_TOP_APP + " [TOP_APP]";
1629 
1630                 // PRIORITY_ADJ_* are adjustments and not used as real priorities.
1631                 // No need to convert to strings.
1632         }
1633         return priority + " [UNKNOWN]";
1634     }
1635 }
1636