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