blob: dadfe3d3746a04dc48ebf1e55b810afcbacc4f12 [file] [log] [blame]
Christopher Tate7060b042014-06-09 19:50:00 -07001/*
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
Dianne Hackbornf9bac162017-04-20 17:17:48 -070019import android.annotation.NonNull;
20import android.annotation.Nullable;
Mathew Inwood61e8ae62018-08-14 14:17:44 +010021import android.annotation.UnsupportedAppUsage;
Christopher Tate7060b042014-06-09 19:50:00 -070022import android.app.job.IJobCallback;
Dianne Hackborna47223f2017-03-30 13:49:13 -070023import android.content.ClipData;
Jeff Sharkey76a02412017-10-24 16:55:04 -060024import android.net.Network;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080025import android.net.Uri;
Dianne Hackbornba604732016-02-10 17:05:10 -080026import android.os.Bundle;
Christopher Tate7060b042014-06-09 19:50:00 -070027import android.os.IBinder;
28import android.os.Parcel;
29import android.os.Parcelable;
30import android.os.PersistableBundle;
Dianne Hackborn7da13d72017-04-04 17:17:35 -070031import android.os.RemoteException;
Christopher Tate7060b042014-06-09 19:50:00 -070032
33/**
34 * Contains the parameters used to configure/identify your job. You do not create this object
35 * yourself, instead it is handed in to your application by the System.
36 */
37public class JobParameters implements Parcelable {
38
Shreyas Basarge5db09082016-01-07 13:38:29 +000039 /** @hide */
Tej Singh33a412b2018-03-16 18:43:59 -070040 public static final int REASON_CANCELED = JobProtoEnums.STOP_REASON_CANCELLED; // 0.
Shreyas Basarge5db09082016-01-07 13:38:29 +000041 /** @hide */
Tej Singh33a412b2018-03-16 18:43:59 -070042 public static final int REASON_CONSTRAINTS_NOT_SATISFIED =
43 JobProtoEnums.STOP_REASON_CONSTRAINTS_NOT_SATISFIED; //1.
Shreyas Basarge5db09082016-01-07 13:38:29 +000044 /** @hide */
Tej Singh33a412b2018-03-16 18:43:59 -070045 public static final int REASON_PREEMPT = JobProtoEnums.STOP_REASON_PREEMPT; // 2.
Shreyas Basarge5db09082016-01-07 13:38:29 +000046 /** @hide */
Tej Singh33a412b2018-03-16 18:43:59 -070047 public static final int REASON_TIMEOUT = JobProtoEnums.STOP_REASON_TIMEOUT; // 3.
Shreyas Basarge5db09082016-01-07 13:38:29 +000048 /** @hide */
Tej Singh33a412b2018-03-16 18:43:59 -070049 public static final int REASON_DEVICE_IDLE = JobProtoEnums.STOP_REASON_DEVICE_IDLE; // 4.
Wei Wang8c0c3c12018-11-14 14:56:52 -080050 /** @hide */
51 public static final int REASON_DEVICE_THERMAL = JobProtoEnums.STOP_REASON_DEVICE_THERMAL; // 5.
Shreyas Basarge5db09082016-01-07 13:38:29 +000052
Dianne Hackborn94326cb2017-06-28 16:17:20 -070053 /** @hide */
54 public static String getReasonName(int reason) {
55 switch (reason) {
56 case REASON_CANCELED: return "canceled";
57 case REASON_CONSTRAINTS_NOT_SATISFIED: return "constraints";
58 case REASON_PREEMPT: return "preempt";
59 case REASON_TIMEOUT: return "timeout";
60 case REASON_DEVICE_IDLE: return "device_idle";
61 default: return "unknown:" + reason;
62 }
63 }
64
Mathew Inwood61e8ae62018-08-14 14:17:44 +010065 @UnsupportedAppUsage
Christopher Tate7060b042014-06-09 19:50:00 -070066 private final int jobId;
67 private final PersistableBundle extras;
Dianne Hackbornba604732016-02-10 17:05:10 -080068 private final Bundle transientExtras;
Dianne Hackborna47223f2017-03-30 13:49:13 -070069 private final ClipData clipData;
70 private final int clipGrantFlags;
Mathew Inwood61e8ae62018-08-14 14:17:44 +010071 @UnsupportedAppUsage
Christopher Tate7060b042014-06-09 19:50:00 -070072 private final IBinder callback;
Matthew Williams03a4da62014-09-10 17:32:18 -070073 private final boolean overrideDeadlineExpired;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080074 private final Uri[] mTriggeredContentUris;
75 private final String[] mTriggeredContentAuthorities;
Jeff Sharkey76a02412017-10-24 16:55:04 -060076 private final Network network;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080077
Shreyas Basarge5db09082016-01-07 13:38:29 +000078 private int stopReason; // Default value of stopReason is REASON_CANCELED
Makoto Onukid2bfec62018-01-12 13:58:01 -080079 private String debugStopReason; // Human readable stop reason for debugging.
Christopher Tate7060b042014-06-09 19:50:00 -070080
81 /** @hide */
Matthew Williams03a4da62014-09-10 17:32:18 -070082 public JobParameters(IBinder callback, int jobId, PersistableBundle extras,
Dianne Hackborna47223f2017-03-30 13:49:13 -070083 Bundle transientExtras, ClipData clipData, int clipGrantFlags,
84 boolean overrideDeadlineExpired, Uri[] triggeredContentUris,
Jeff Sharkey76a02412017-10-24 16:55:04 -060085 String[] triggeredContentAuthorities, Network network) {
Christopher Tate7060b042014-06-09 19:50:00 -070086 this.jobId = jobId;
87 this.extras = extras;
Dianne Hackbornba604732016-02-10 17:05:10 -080088 this.transientExtras = transientExtras;
Dianne Hackborna47223f2017-03-30 13:49:13 -070089 this.clipData = clipData;
90 this.clipGrantFlags = clipGrantFlags;
Christopher Tate7060b042014-06-09 19:50:00 -070091 this.callback = callback;
Matthew Williams03a4da62014-09-10 17:32:18 -070092 this.overrideDeadlineExpired = overrideDeadlineExpired;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -080093 this.mTriggeredContentUris = triggeredContentUris;
94 this.mTriggeredContentAuthorities = triggeredContentAuthorities;
Jeff Sharkey76a02412017-10-24 16:55:04 -060095 this.network = network;
Christopher Tate7060b042014-06-09 19:50:00 -070096 }
97
98 /**
99 * @return The unique id of this job, specified at creation time.
100 */
101 public int getJobId() {
102 return jobId;
103 }
104
105 /**
Shreyas Basarge5db09082016-01-07 13:38:29 +0000106 * Reason onStopJob() was called on this job.
107 * @hide
108 */
109 public int getStopReason() {
110 return stopReason;
111 }
112
113 /**
Makoto Onukid2bfec62018-01-12 13:58:01 -0800114 * Reason onStopJob() was called on this job.
115 * @hide
116 */
117 public String getDebugStopReason() {
118 return debugStopReason;
119 }
120
121 /**
Christopher Tate7060b042014-06-09 19:50:00 -0700122 * @return The extras you passed in when constructing this job with
123 * {@link android.app.job.JobInfo.Builder#setExtras(android.os.PersistableBundle)}. This will
124 * never be null. If you did not set any extras this will be an empty bundle.
125 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700126 public @NonNull PersistableBundle getExtras() {
Christopher Tate7060b042014-06-09 19:50:00 -0700127 return extras;
128 }
129
Matthew Williams03a4da62014-09-10 17:32:18 -0700130 /**
Dianne Hackbornba604732016-02-10 17:05:10 -0800131 * @return The transient extras you passed in when constructing this job with
132 * {@link android.app.job.JobInfo.Builder#setTransientExtras(android.os.Bundle)}. This will
133 * never be null. If you did not set any extras this will be an empty bundle.
134 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700135 public @NonNull Bundle getTransientExtras() {
Dianne Hackbornba604732016-02-10 17:05:10 -0800136 return transientExtras;
137 }
138
139 /**
Dianne Hackborna47223f2017-03-30 13:49:13 -0700140 * @return The clip you passed in when constructing this job with
141 * {@link android.app.job.JobInfo.Builder#setClipData(ClipData, int)}. Will be null
142 * if it was not set.
143 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700144 public @Nullable ClipData getClipData() {
Dianne Hackborna47223f2017-03-30 13:49:13 -0700145 return clipData;
146 }
147
148 /**
149 * @return The clip grant flags you passed in when constructing this job with
150 * {@link android.app.job.JobInfo.Builder#setClipData(ClipData, int)}. Will be 0
151 * if it was not set.
152 */
153 public int getClipGrantFlags() {
154 return clipGrantFlags;
155 }
156
157 /**
Matthew Williams03a4da62014-09-10 17:32:18 -0700158 * For jobs with {@link android.app.job.JobInfo.Builder#setOverrideDeadline(long)} set, this
159 * provides an easy way to tell whether the job is being executed due to the deadline
160 * expiring. Note: If the job is running because its deadline expired, it implies that its
161 * constraints will not be met.
162 */
163 public boolean isOverrideDeadlineExpired() {
164 return overrideDeadlineExpired;
165 }
166
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800167 /**
168 * For jobs with {@link android.app.job.JobInfo.Builder#addTriggerContentUri} set, this
169 * reports which URIs have triggered the job. This will be null if either no URIs have
170 * triggered it (it went off due to a deadline or other reason), or the number of changed
171 * URIs is too large to report. Whether or not the number of URIs is too large, you can
172 * always use {@link #getTriggeredContentAuthorities()} to determine whether the job was
173 * triggered due to any content changes and the authorities they are associated with.
174 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700175 public @Nullable Uri[] getTriggeredContentUris() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800176 return mTriggeredContentUris;
177 }
178
179 /**
180 * For jobs with {@link android.app.job.JobInfo.Builder#addTriggerContentUri} set, this
181 * reports which content authorities have triggered the job. It will only be null if no
182 * authorities have triggered it -- that is, the job executed for some other reason, such
183 * as a deadline expiring. If this is non-null, you can use {@link #getTriggeredContentUris()}
184 * to retrieve the details of which URIs changed (as long as that has not exceeded the maximum
185 * number it can reported).
186 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700187 public @Nullable String[] getTriggeredContentAuthorities() {
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800188 return mTriggeredContentAuthorities;
189 }
190
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700191 /**
Jeff Sharkey76a02412017-10-24 16:55:04 -0600192 * Return the network that should be used to perform any network requests
193 * for this job.
194 * <p>
195 * Devices may have multiple active network connections simultaneously, or
196 * they may not have a default network route at all. To correctly handle all
197 * situations like this, your job should always use the network returned by
198 * this method instead of implicitly using the default network route.
199 * <p>
200 * Note that the system may relax the constraints you originally requested,
201 * such as allowing a {@link JobInfo#NETWORK_TYPE_UNMETERED} job to run over
202 * a metered network when there is a surplus of metered data available.
203 *
204 * @return the network that should be used to perform any network requests
205 * for this job, or {@code null} if this job didn't set any required
206 * network type.
207 * @see JobInfo.Builder#setRequiredNetworkType(int)
208 */
209 public @Nullable Network getNetwork() {
210 return network;
211 }
212
213 /**
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700214 * Dequeue the next pending {@link JobWorkItem} from these JobParameters associated with their
215 * currently running job. Calling this method when there is no more work available and all
216 * previously dequeued work has been completed will result in the system taking care of
217 * stopping the job for you --
218 * you should not call {@link JobService#jobFinished(JobParameters, boolean)} yourself
219 * (otherwise you risk losing an upcoming JobWorkItem that is being enqueued at the same time).
220 *
Dianne Hackbornfd8807a2017-04-17 13:34:51 -0700221 * <p>Once you are done with the {@link JobWorkItem} returned by this method, you must call
222 * {@link #completeWork(JobWorkItem)} with it to inform the system that you are done
223 * executing the work. The job will not be finished until all dequeued work has been
224 * completed. You do not, however, have to complete each returned work item before deqeueing
225 * the next one -- you can use {@link #dequeueWork()} multiple times before completing
226 * previous work if you want to process work in parallel, and you can complete the work
227 * in whatever order you want.</p>
228 *
229 * <p>If the job runs to the end of its available time period before all work has been
230 * completed, it will stop as normal. You should return true from
231 * {@link JobService#onStopJob(JobParameters)} in order to have the job rescheduled, and by
232 * doing so any pending as well as remaining uncompleted work will be re-queued
233 * for the next time the job runs.</p>
234 *
Dianne Hackborn28d1b662017-04-21 14:17:23 -0700235 * <p>This example shows how to construct a JobService that will serially dequeue and
236 * process work that is available for it:</p>
237 *
238 * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/JobWorkService.java
239 * service}
240 *
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700241 * @return Returns a new {@link JobWorkItem} if there is one pending, otherwise null.
242 * If null is returned, the system will also stop the job if all work has also been completed.
243 * (This means that for correct operation, you must always call dequeueWork() after you have
244 * completed other work, to check either for more work or allow the system to stop the job.)
245 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700246 public @Nullable JobWorkItem dequeueWork() {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700247 try {
248 return getCallback().dequeueWork(getJobId());
249 } catch (RemoteException e) {
250 throw e.rethrowFromSystemServer();
251 }
252 }
253
254 /**
255 * Report the completion of executing a {@link JobWorkItem} previously returned by
256 * {@link #dequeueWork()}. This tells the system you are done with the
257 * work associated with that item, so it will not be returned again. Note that if this
258 * is the last work in the queue, completing it here will <em>not</em> finish the overall
259 * job -- for that to happen, you still need to call {@link #dequeueWork()}
260 * again.
261 *
262 * <p>If you are enqueueing work into a job, you must call this method for each piece
263 * of work you process. Do <em>not</em> call
264 * {@link JobService#jobFinished(JobParameters, boolean)}
265 * or else you can lose work in your queue.</p>
266 *
267 * @param work The work you have completed processing, as previously returned by
268 * {@link #dequeueWork()}
269 */
Dianne Hackbornf9bac162017-04-20 17:17:48 -0700270 public void completeWork(@NonNull JobWorkItem work) {
Dianne Hackborn7da13d72017-04-04 17:17:35 -0700271 try {
272 if (!getCallback().completeWork(getJobId(), work.getWorkId())) {
273 throw new IllegalArgumentException("Given work is not active: " + work);
274 }
275 } catch (RemoteException e) {
276 throw e.rethrowFromSystemServer();
277 }
278 }
279
Christopher Tate7060b042014-06-09 19:50:00 -0700280 /** @hide */
Mathew Inwood61e8ae62018-08-14 14:17:44 +0100281 @UnsupportedAppUsage
Christopher Tate7060b042014-06-09 19:50:00 -0700282 public IJobCallback getCallback() {
283 return IJobCallback.Stub.asInterface(callback);
284 }
285
286 private JobParameters(Parcel in) {
287 jobId = in.readInt();
288 extras = in.readPersistableBundle();
Dianne Hackbornba604732016-02-10 17:05:10 -0800289 transientExtras = in.readBundle();
Dianne Hackborna47223f2017-03-30 13:49:13 -0700290 if (in.readInt() != 0) {
291 clipData = ClipData.CREATOR.createFromParcel(in);
292 clipGrantFlags = in.readInt();
293 } else {
294 clipData = null;
295 clipGrantFlags = 0;
296 }
Christopher Tate7060b042014-06-09 19:50:00 -0700297 callback = in.readStrongBinder();
Matthew Williams03a4da62014-09-10 17:32:18 -0700298 overrideDeadlineExpired = in.readInt() == 1;
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800299 mTriggeredContentUris = in.createTypedArray(Uri.CREATOR);
300 mTriggeredContentAuthorities = in.createStringArray();
Jeff Sharkey76a02412017-10-24 16:55:04 -0600301 if (in.readInt() != 0) {
302 network = Network.CREATOR.createFromParcel(in);
303 } else {
304 network = null;
305 }
Shreyas Basarge5db09082016-01-07 13:38:29 +0000306 stopReason = in.readInt();
Makoto Onukid2bfec62018-01-12 13:58:01 -0800307 debugStopReason = in.readString();
Shreyas Basarge5db09082016-01-07 13:38:29 +0000308 }
309
310 /** @hide */
Makoto Onukid2bfec62018-01-12 13:58:01 -0800311 public void setStopReason(int reason, String debugStopReason) {
Shreyas Basarge5db09082016-01-07 13:38:29 +0000312 stopReason = reason;
Makoto Onukid2bfec62018-01-12 13:58:01 -0800313 this.debugStopReason = debugStopReason;
Christopher Tate7060b042014-06-09 19:50:00 -0700314 }
315
316 @Override
317 public int describeContents() {
318 return 0;
319 }
320
321 @Override
322 public void writeToParcel(Parcel dest, int flags) {
323 dest.writeInt(jobId);
324 dest.writePersistableBundle(extras);
Dianne Hackbornba604732016-02-10 17:05:10 -0800325 dest.writeBundle(transientExtras);
Dianne Hackborna47223f2017-03-30 13:49:13 -0700326 if (clipData != null) {
327 dest.writeInt(1);
328 clipData.writeToParcel(dest, flags);
329 dest.writeInt(clipGrantFlags);
330 } else {
331 dest.writeInt(0);
332 }
Christopher Tate7060b042014-06-09 19:50:00 -0700333 dest.writeStrongBinder(callback);
Matthew Williams03a4da62014-09-10 17:32:18 -0700334 dest.writeInt(overrideDeadlineExpired ? 1 : 0);
Dianne Hackborn1a30bd92016-01-11 11:05:00 -0800335 dest.writeTypedArray(mTriggeredContentUris, flags);
336 dest.writeStringArray(mTriggeredContentAuthorities);
Jeff Sharkey76a02412017-10-24 16:55:04 -0600337 if (network != null) {
338 dest.writeInt(1);
339 network.writeToParcel(dest, flags);
340 } else {
341 dest.writeInt(0);
342 }
Shreyas Basarge5db09082016-01-07 13:38:29 +0000343 dest.writeInt(stopReason);
Makoto Onukid2bfec62018-01-12 13:58:01 -0800344 dest.writeString(debugStopReason);
Christopher Tate7060b042014-06-09 19:50:00 -0700345 }
346
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700347 public static final @android.annotation.NonNull Creator<JobParameters> CREATOR = new Creator<JobParameters>() {
Christopher Tate7060b042014-06-09 19:50:00 -0700348 @Override
349 public JobParameters createFromParcel(Parcel in) {
350 return new JobParameters(in);
351 }
352
353 @Override
354 public JobParameters[] newArray(int size) {
355 return new JobParameters[size];
356 }
357 };
358}