JobInfo.java revision 900c67fc51fc2672458dd1c9641250f2ecc01a31
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    /** Builder class for constructing {@link JobInfo} objects. */
270    public static final class Builder {
271        private int mJobId;
272        private PersistableBundle mExtras = PersistableBundle.EMPTY;
273        private ComponentName mJobService;
274        // Requirements.
275        private boolean mRequiresCharging;
276        private boolean mRequiresDeviceIdle;
277        private int mNetworkCapabilities;
278        private boolean mIsPersisted;
279        // One-off parameters.
280        private long mMinLatencyMillis;
281        private long mMaxExecutionDelayMillis;
282        // Periodic parameters.
283        private boolean mIsPeriodic;
284        private boolean mHasEarlyConstraint;
285        private boolean mHasLateConstraint;
286        private long mIntervalMillis;
287        // Back-off parameters.
288        private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS;
289        private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY;
290        /** Easy way to track whether the client has tried to set a back-off policy. */
291        private boolean mBackoffPolicySet = false;
292
293        /**
294         * @param jobId Application-provided id for this job. Subsequent calls to cancel, or
295         *               jobs created with the same jobId, will update the pre-existing job with
296         *               the same id.
297         * @param jobService The endpoint that you implement that will receive the callback from the
298         *            JobScheduler.
299         */
300        public Builder(int jobId, ComponentName jobService) {
301            mJobService = jobService;
302            mJobId = jobId;
303        }
304
305        /**
306         * Set optional extras. This is persisted, so we only allow primitive types.
307         * @param extras Bundle containing extras you want the scheduler to hold on to for you.
308         */
309        public Builder setExtras(PersistableBundle extras) {
310            mExtras = extras;
311            return this;
312        }
313
314        /**
315         * Set some description of the kind of network capabilities you would like to have. This
316         * will be a parameter defined in {@link android.app.job.JobInfo.NetworkType}.
317         * Not calling this function means the network is not necessary.
318         * Bear in mind that calling this function defines network as a strict requirement for your
319         * job if the network requested is not available your job will never run. See
320         * {@link #setOverrideDeadline(long)} to change this behaviour.
321         */
322        public Builder setRequiredNetworkCapabilities(int networkCapabilities) {
323            mNetworkCapabilities = networkCapabilities;
324            return this;
325        }
326
327        /**
328         * Specify that to run this job, the device needs to be plugged in. This defaults to
329         * false.
330         * @param requiresCharging Whether or not the device is plugged in.
331         */
332        public Builder setRequiresCharging(boolean requiresCharging) {
333            mRequiresCharging = requiresCharging;
334            return this;
335        }
336
337        /**
338         * Specify that to run, the job needs the device to be in idle mode. This defaults to
339         * false.
340         * <p>Idle mode is a loose definition provided by the system, which means that the device
341         * is not in use, and has not been in use for some time. As such, it is a good time to
342         * perform resource heavy jobs. Bear in mind that battery usage will still be attributed
343         * to your application, and surfaced to the user in battery stats.</p>
344         * @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
345         *                           window.
346         */
347        public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
348            mRequiresDeviceIdle = requiresDeviceIdle;
349            return this;
350        }
351
352        /**
353         * Specify that this job should recur with the provided interval, not more than once per
354         * period. You have no control over when within this interval this job will be executed,
355         * only the guarantee that it will be executed at most once within this interval.
356         * Setting this function on the builder with {@link #setMinimumLatency(long)} or
357         * {@link #setOverrideDeadline(long)} will result in an error.
358         * @param intervalMillis Millisecond interval for which this job will repeat.
359         */
360        public Builder setPeriodic(long intervalMillis) {
361            mIsPeriodic = true;
362            mIntervalMillis = intervalMillis;
363            mHasEarlyConstraint = mHasLateConstraint = true;
364            return this;
365        }
366
367        /**
368         * Specify that this job should be delayed by the provided amount of time.
369         * Because it doesn't make sense setting this property on a periodic job, doing so will
370         * throw an {@link java.lang.IllegalArgumentException} when
371         * {@link android.app.job.JobInfo.Builder#build()} is called.
372         * @param minLatencyMillis Milliseconds before which this job will not be considered for
373         *                         execution.
374         */
375        public Builder setMinimumLatency(long minLatencyMillis) {
376            mMinLatencyMillis = minLatencyMillis;
377            mHasEarlyConstraint = true;
378            return this;
379        }
380
381        /**
382         * Set deadline which is the maximum scheduling latency. The job will be run by this
383         * deadline even if other requirements are not met. Because it doesn't make sense setting
384         * this property on a periodic job, doing so will throw an
385         * {@link java.lang.IllegalArgumentException} when
386         * {@link android.app.job.JobInfo.Builder#build()} is called.
387         */
388        public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
389            mMaxExecutionDelayMillis = maxExecutionDelayMillis;
390            mHasLateConstraint = true;
391            return this;
392        }
393
394        /**
395         * Set up the back-off/retry policy.
396         * This defaults to some respectable values: {5 seconds, Exponential}. We cap back-off at
397         * 1hr.
398         * Note that trying to set a backoff criteria for a job with
399         * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
400         * This is because back-off typically does not make sense for these types of jobs. See
401         * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
402         * for more description of the return value for the case of a job executing while in idle
403         * mode.
404         * @param initialBackoffMillis Millisecond time interval to wait initially when job has
405         *                             failed.
406         * @param backoffPolicy is one of {@link BackoffPolicy}
407         */
408        public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) {
409            mBackoffPolicySet = true;
410            mInitialBackoffMillis = initialBackoffMillis;
411            mBackoffPolicy = backoffPolicy;
412            return this;
413        }
414
415        /**
416         * Set whether or not to persist this job across device reboots. This will only have an
417         * effect if your application holds the permission
418         * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED}. Otherwise an exception will
419         * be thrown.
420         * @param isPersisted True to indicate that the job will be written to disk and loaded at
421         *                    boot.
422         */
423        public Builder setIsPersisted(boolean isPersisted) {
424            mIsPersisted = isPersisted;
425            return this;
426        }
427
428        /**
429         * @return The job object to hand to the JobScheduler. This object is immutable.
430         */
431        public JobInfo build() {
432            mExtras = new PersistableBundle(mExtras);  // Make our own copy.
433            // Check that a deadline was not set on a periodic job.
434            if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
435                throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
436                        "periodic job.");
437            }
438            if (mIsPeriodic && (mMinLatencyMillis != 0L)) {
439                throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
440                        "periodic job");
441            }
442            if (mBackoffPolicySet && mRequiresDeviceIdle) {
443                throw new IllegalArgumentException("An idle mode job will not respect any" +
444                        " back-off policy, so calling setBackoffCriteria with" +
445                        " setRequiresDeviceIdle is an error.");
446            }
447            return new JobInfo(this);
448        }
449    }
450
451}
452