JobInfo.java revision ee410da42b6b8352213f03f7725fd041f703b035
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
17package android.app.job;
18
19import android.content.ComponentName;
20import android.os.Bundle;
21import android.os.Parcel;
22import android.os.Parcelable;
23import android.os.PersistableBundle;
24
25/**
26 * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
27 * parameters required to schedule work against the calling application. These are constructed
28 * using the {@link JobInfo.Builder}.
29 */
30public class JobInfo implements Parcelable {
31    public interface NetworkType {
32        /** Default. */
33        public final int NONE = 0;
34        /** This job requires network connectivity. */
35        public final int ANY = 1;
36        /** This job requires network connectivity that is unmetered. */
37        public final int UNMETERED = 2;
38    }
39
40    /**
41     * Amount of backoff a job has initially by default, in milliseconds.
42     * @hide.
43     */
44    public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 5000L;
45
46    /**
47     * Default type of backoff.
48     * @hide
49     */
50    public static final int DEFAULT_BACKOFF_POLICY = BackoffPolicy.EXPONENTIAL;
51    /**
52     * Maximum backoff we allow for a job, in milliseconds.
53     * @hide
54     */
55    public static final long MAX_BACKOFF_DELAY_MILLIS = 24 * 60 * 60 * 1000;  // 24 hours.
56
57    /**
58     * Linear: retry_time(failure_time, t) = failure_time + initial_retry_delay * t, t >= 1
59     * Expon: retry_time(failure_time, t) = failure_time + initial_retry_delay ^ t, t >= 1
60     */
61    public interface BackoffPolicy {
62        public final int LINEAR = 0;
63        public final int EXPONENTIAL = 1;
64    }
65
66    private final int jobId;
67    private final PersistableBundle extras;
68    private final ComponentName service;
69    private final boolean requireCharging;
70    private final boolean requireDeviceIdle;
71    private final boolean hasEarlyConstraint;
72    private final boolean hasLateConstraint;
73    private final int networkCapabilities;
74    private final long minLatencyMillis;
75    private final long maxExecutionDelayMillis;
76    private final boolean isPeriodic;
77    private final boolean isPersisted;
78    private final long intervalMillis;
79    private final long initialBackoffMillis;
80    private final int backoffPolicy;
81
82    /**
83     * Unique job id associated with this class. This is assigned to your job by the scheduler.
84     */
85    public int getId() {
86        return jobId;
87    }
88
89    /**
90     * Bundle of extras which are returned to your application at execution time.
91     */
92    public PersistableBundle getExtras() {
93        return extras;
94    }
95
96    /**
97     * Name of the service endpoint that will be called back into by the JobScheduler.
98     */
99    public ComponentName getService() {
100        return service;
101    }
102
103    /**
104     * Whether this job needs the device to be plugged in.
105     */
106    public boolean isRequireCharging() {
107        return requireCharging;
108    }
109
110    /**
111     * Whether this job needs the device to be in an Idle maintenance window.
112     */
113    public boolean isRequireDeviceIdle() {
114        return requireDeviceIdle;
115    }
116
117    /**
118     * See {@link android.app.job.JobInfo.NetworkType} for a description of this value.
119     */
120    public int getNetworkCapabilities() {
121        return networkCapabilities;
122    }
123
124    /**
125     * Set for a job that does not recur periodically, to specify a delay after which the job
126     * will be eligible for execution. This value is not set if the job recurs periodically.
127     */
128    public long getMinLatencyMillis() {
129        return minLatencyMillis;
130    }
131
132    /**
133     * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the job recurs
134     * periodically.
135     */
136    public long getMaxExecutionDelayMillis() {
137        return maxExecutionDelayMillis;
138    }
139
140    /**
141     * Track whether this job will repeat with a given period.
142     */
143    public boolean isPeriodic() {
144        return isPeriodic;
145    }
146
147    /**
148     * @return Whether or not this job should be persisted across device reboots.
149     */
150    public boolean isPersisted() {
151        return isPersisted;
152    }
153
154    /**
155     * Set to the interval between occurrences of this job. This value is <b>not</b> set if the
156     * job does not recur periodically.
157     */
158    public long getIntervalMillis() {
159        return intervalMillis;
160    }
161
162    /**
163     * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
164     * will be increased depending on the backoff policy specified at job creation time. Defaults
165     * to 5 seconds.
166     */
167    public long getInitialBackoffMillis() {
168        return initialBackoffMillis;
169    }
170
171    /**
172     * See {@link android.app.job.JobInfo.BackoffPolicy} for an explanation of the values this field
173     * can take. This defaults to exponential.
174     */
175    public int getBackoffPolicy() {
176        return backoffPolicy;
177    }
178
179    /**
180     * User can specify an early constraint of 0L, which is valid, so we keep track of whether the
181     * function was called at all.
182     * @hide
183     */
184    public boolean hasEarlyConstraint() {
185        return hasEarlyConstraint;
186    }
187
188    /**
189     * User can specify a late constraint of 0L, which is valid, so we keep track of whether the
190     * function was called at all.
191     * @hide
192     */
193    public boolean hasLateConstraint() {
194        return hasLateConstraint;
195    }
196
197    private JobInfo(Parcel in) {
198        jobId = in.readInt();
199        extras = in.readPersistableBundle();
200        service = in.readParcelable(null);
201        requireCharging = in.readInt() == 1;
202        requireDeviceIdle = in.readInt() == 1;
203        networkCapabilities = in.readInt();
204        minLatencyMillis = in.readLong();
205        maxExecutionDelayMillis = in.readLong();
206        isPeriodic = in.readInt() == 1;
207        isPersisted = in.readInt() == 1;
208        intervalMillis = in.readLong();
209        initialBackoffMillis = in.readLong();
210        backoffPolicy = in.readInt();
211        hasEarlyConstraint = in.readInt() == 1;
212        hasLateConstraint = in.readInt() == 1;
213    }
214
215    private JobInfo(JobInfo.Builder b) {
216        jobId = b.mJobId;
217        extras = b.mExtras;
218        service = b.mJobService;
219        requireCharging = b.mRequiresCharging;
220        requireDeviceIdle = b.mRequiresDeviceIdle;
221        networkCapabilities = b.mNetworkCapabilities;
222        minLatencyMillis = b.mMinLatencyMillis;
223        maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
224        isPeriodic = b.mIsPeriodic;
225        isPersisted = b.mIsPersisted;
226        intervalMillis = b.mIntervalMillis;
227        initialBackoffMillis = b.mInitialBackoffMillis;
228        backoffPolicy = b.mBackoffPolicy;
229        hasEarlyConstraint = b.mHasEarlyConstraint;
230        hasLateConstraint = b.mHasLateConstraint;
231    }
232
233    @Override
234    public int describeContents() {
235        return 0;
236    }
237
238    @Override
239    public void writeToParcel(Parcel out, int flags) {
240        out.writeInt(jobId);
241        out.writePersistableBundle(extras);
242        out.writeParcelable(service, flags);
243        out.writeInt(requireCharging ? 1 : 0);
244        out.writeInt(requireDeviceIdle ? 1 : 0);
245        out.writeInt(networkCapabilities);
246        out.writeLong(minLatencyMillis);
247        out.writeLong(maxExecutionDelayMillis);
248        out.writeInt(isPeriodic ? 1 : 0);
249        out.writeInt(isPersisted ? 1 : 0);
250        out.writeLong(intervalMillis);
251        out.writeLong(initialBackoffMillis);
252        out.writeInt(backoffPolicy);
253        out.writeInt(hasEarlyConstraint ? 1 : 0);
254        out.writeInt(hasLateConstraint ? 1 : 0);
255    }
256
257    public static final Creator<JobInfo> CREATOR = new Creator<JobInfo>() {
258        @Override
259        public JobInfo createFromParcel(Parcel in) {
260            return new JobInfo(in);
261        }
262
263        @Override
264        public JobInfo[] newArray(int size) {
265            return new JobInfo[size];
266        }
267    };
268
269    @Override
270    public String toString() {
271        return "(job:" + jobId + "/" + service.flattenToShortString() + ")";
272    }
273
274    /** Builder class for constructing {@link JobInfo} objects. */
275    public static final class Builder {
276        private int mJobId;
277        private PersistableBundle mExtras = PersistableBundle.EMPTY;
278        private ComponentName mJobService;
279        // Requirements.
280        private boolean mRequiresCharging;
281        private boolean mRequiresDeviceIdle;
282        private int mNetworkCapabilities;
283        private boolean mIsPersisted;
284        // One-off parameters.
285        private long mMinLatencyMillis;
286        private long mMaxExecutionDelayMillis;
287        // Periodic parameters.
288        private boolean mIsPeriodic;
289        private boolean mHasEarlyConstraint;
290        private boolean mHasLateConstraint;
291        private long mIntervalMillis;
292        // Back-off parameters.
293        private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS;
294        private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY;
295        /** Easy way to track whether the client has tried to set a back-off policy. */
296        private boolean mBackoffPolicySet = false;
297
298        /**
299         * @param jobId Application-provided id for this job. Subsequent calls to cancel, or
300         *               jobs created with the same jobId, will update the pre-existing job with
301         *               the same id.
302         * @param jobService The endpoint that you implement that will receive the callback from the
303         *            JobScheduler.
304         */
305        public Builder(int jobId, ComponentName jobService) {
306            mJobService = jobService;
307            mJobId = jobId;
308        }
309
310        /**
311         * Set optional extras. This is persisted, so we only allow primitive types.
312         * @param extras Bundle containing extras you want the scheduler to hold on to for you.
313         */
314        public Builder setExtras(PersistableBundle extras) {
315            mExtras = extras;
316            return this;
317        }
318
319        /**
320         * Set some description of the kind of network capabilities you would like to have. This
321         * will be a parameter defined in {@link android.app.job.JobInfo.NetworkType}.
322         * Not calling this function means the network is not necessary.
323         * Bear in mind that calling this function defines network as a strict requirement for your
324         * job if the network requested is not available your job will never run. See
325         * {@link #setOverrideDeadline(long)} to change this behaviour.
326         */
327        public Builder setRequiredNetworkCapabilities(int networkCapabilities) {
328            mNetworkCapabilities = networkCapabilities;
329            return this;
330        }
331
332        /**
333         * Specify that to run this job, the device needs to be plugged in. This defaults to
334         * false.
335         * @param requiresCharging Whether or not the device is plugged in.
336         */
337        public Builder setRequiresCharging(boolean requiresCharging) {
338            mRequiresCharging = requiresCharging;
339            return this;
340        }
341
342        /**
343         * Specify that to run, the job needs the device to be in idle mode. This defaults to
344         * false.
345         * <p>Idle mode is a loose definition provided by the system, which means that the device
346         * is not in use, and has not been in use for some time. As such, it is a good time to
347         * perform resource heavy jobs. Bear in mind that battery usage will still be attributed
348         * to your application, and surfaced to the user in battery stats.</p>
349         * @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
350         *                           window.
351         */
352        public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
353            mRequiresDeviceIdle = requiresDeviceIdle;
354            return this;
355        }
356
357        /**
358         * Specify that this job should recur with the provided interval, not more than once per
359         * period. You have no control over when within this interval this job will be executed,
360         * only the guarantee that it will be executed at most once within this interval.
361         * Setting this function on the builder with {@link #setMinimumLatency(long)} or
362         * {@link #setOverrideDeadline(long)} will result in an error.
363         * @param intervalMillis Millisecond interval for which this job will repeat.
364         */
365        public Builder setPeriodic(long intervalMillis) {
366            mIsPeriodic = true;
367            mIntervalMillis = intervalMillis;
368            mHasEarlyConstraint = mHasLateConstraint = true;
369            return this;
370        }
371
372        /**
373         * Specify that this job should be delayed by the provided amount of time.
374         * Because it doesn't make sense setting this property on a periodic job, doing so will
375         * throw an {@link java.lang.IllegalArgumentException} when
376         * {@link android.app.job.JobInfo.Builder#build()} is called.
377         * @param minLatencyMillis Milliseconds before which this job will not be considered for
378         *                         execution.
379         */
380        public Builder setMinimumLatency(long minLatencyMillis) {
381            mMinLatencyMillis = minLatencyMillis;
382            mHasEarlyConstraint = true;
383            return this;
384        }
385
386        /**
387         * Set deadline which is the maximum scheduling latency. The job will be run by this
388         * deadline even if other requirements are not met. Because it doesn't make sense setting
389         * this property on a periodic job, doing so will throw an
390         * {@link java.lang.IllegalArgumentException} when
391         * {@link android.app.job.JobInfo.Builder#build()} is called.
392         */
393        public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
394            mMaxExecutionDelayMillis = maxExecutionDelayMillis;
395            mHasLateConstraint = true;
396            return this;
397        }
398
399        /**
400         * Set up the back-off/retry policy.
401         * This defaults to some respectable values: {5 seconds, Exponential}. We cap back-off at
402         * 1hr.
403         * Note that trying to set a backoff criteria for a job with
404         * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
405         * This is because back-off typically does not make sense for these types of jobs. See
406         * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
407         * for more description of the return value for the case of a job executing while in idle
408         * mode.
409         * @param initialBackoffMillis Millisecond time interval to wait initially when job has
410         *                             failed.
411         * @param backoffPolicy is one of {@link BackoffPolicy}
412         */
413        public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) {
414            mBackoffPolicySet = true;
415            mInitialBackoffMillis = initialBackoffMillis;
416            mBackoffPolicy = backoffPolicy;
417            return this;
418        }
419
420        /**
421         * Set whether or not to persist this job across device reboots. This will only have an
422         * effect if your application holds the permission
423         * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED}. Otherwise an exception will
424         * be thrown.
425         * @param isPersisted True to indicate that the job will be written to disk and loaded at
426         *                    boot.
427         */
428        public Builder setIsPersisted(boolean isPersisted) {
429            mIsPersisted = isPersisted;
430            return this;
431        }
432
433        /**
434         * @return The job object to hand to the JobScheduler. This object is immutable.
435         */
436        public JobInfo build() {
437            mExtras = new PersistableBundle(mExtras);  // Make our own copy.
438            // Check that a deadline was not set on a periodic job.
439            if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
440                throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
441                        "periodic job.");
442            }
443            if (mIsPeriodic && (mMinLatencyMillis != 0L)) {
444                throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
445                        "periodic job");
446            }
447            if (mBackoffPolicySet && mRequiresDeviceIdle) {
448                throw new IllegalArgumentException("An idle mode job will not respect any" +
449                        " back-off policy, so calling setBackoffCriteria with" +
450                        " setRequiresDeviceIdle is an error.");
451            }
452            return new JobInfo(this);
453        }
454    }
455
456}
457