• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package android.app.job;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.UnsupportedAppUsage;
22 import android.app.job.IJobCallback;
23 import android.content.ClipData;
24 import android.net.Network;
25 import android.net.Uri;
26 import android.os.Bundle;
27 import android.os.IBinder;
28 import android.os.Parcel;
29 import android.os.Parcelable;
30 import android.os.PersistableBundle;
31 import android.os.RemoteException;
32 
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  */
37 public class JobParameters implements Parcelable {
38 
39     /** @hide */
40     public static final int REASON_CANCELED = JobProtoEnums.STOP_REASON_CANCELLED; // 0.
41     /** @hide */
42     public static final int REASON_CONSTRAINTS_NOT_SATISFIED =
43             JobProtoEnums.STOP_REASON_CONSTRAINTS_NOT_SATISFIED; //1.
44     /** @hide */
45     public static final int REASON_PREEMPT = JobProtoEnums.STOP_REASON_PREEMPT; // 2.
46     /** @hide */
47     public static final int REASON_TIMEOUT = JobProtoEnums.STOP_REASON_TIMEOUT; // 3.
48     /** @hide */
49     public static final int REASON_DEVICE_IDLE = JobProtoEnums.STOP_REASON_DEVICE_IDLE; // 4.
50     /** @hide */
51     public static final int REASON_DEVICE_THERMAL = JobProtoEnums.STOP_REASON_DEVICE_THERMAL; // 5.
52 
53     /** @hide */
getReasonName(int reason)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 
65     @UnsupportedAppUsage
66     private final int jobId;
67     private final PersistableBundle extras;
68     private final Bundle transientExtras;
69     private final ClipData clipData;
70     private final int clipGrantFlags;
71     @UnsupportedAppUsage
72     private final IBinder callback;
73     private final boolean overrideDeadlineExpired;
74     private final Uri[] mTriggeredContentUris;
75     private final String[] mTriggeredContentAuthorities;
76     private final Network network;
77 
78     private int stopReason; // Default value of stopReason is REASON_CANCELED
79     private String debugStopReason; // Human readable stop reason for debugging.
80 
81     /** @hide */
JobParameters(IBinder callback, int jobId, PersistableBundle extras, Bundle transientExtras, ClipData clipData, int clipGrantFlags, boolean overrideDeadlineExpired, Uri[] triggeredContentUris, String[] triggeredContentAuthorities, Network network)82     public JobParameters(IBinder callback, int jobId, PersistableBundle extras,
83             Bundle transientExtras, ClipData clipData, int clipGrantFlags,
84             boolean overrideDeadlineExpired, Uri[] triggeredContentUris,
85             String[] triggeredContentAuthorities, Network network) {
86         this.jobId = jobId;
87         this.extras = extras;
88         this.transientExtras = transientExtras;
89         this.clipData = clipData;
90         this.clipGrantFlags = clipGrantFlags;
91         this.callback = callback;
92         this.overrideDeadlineExpired = overrideDeadlineExpired;
93         this.mTriggeredContentUris = triggeredContentUris;
94         this.mTriggeredContentAuthorities = triggeredContentAuthorities;
95         this.network = network;
96     }
97 
98     /**
99      * @return The unique id of this job, specified at creation time.
100      */
getJobId()101     public int getJobId() {
102         return jobId;
103     }
104 
105     /**
106      * Reason onStopJob() was called on this job.
107      * @hide
108      */
getStopReason()109     public int getStopReason() {
110         return stopReason;
111     }
112 
113     /**
114      * Reason onStopJob() was called on this job.
115      * @hide
116      */
getDebugStopReason()117     public String getDebugStopReason() {
118         return debugStopReason;
119     }
120 
121     /**
122      * @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      */
getExtras()126     public @NonNull PersistableBundle getExtras() {
127         return extras;
128     }
129 
130     /**
131      * @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      */
getTransientExtras()135     public @NonNull Bundle getTransientExtras() {
136         return transientExtras;
137     }
138 
139     /**
140      * @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      */
getClipData()144     public @Nullable ClipData getClipData() {
145         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      */
getClipGrantFlags()153     public int getClipGrantFlags() {
154         return clipGrantFlags;
155     }
156 
157     /**
158      * 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      */
isOverrideDeadlineExpired()163     public boolean isOverrideDeadlineExpired() {
164         return overrideDeadlineExpired;
165     }
166 
167     /**
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      */
getTriggeredContentUris()175     public @Nullable Uri[] getTriggeredContentUris() {
176         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      */
getTriggeredContentAuthorities()187     public @Nullable String[] getTriggeredContentAuthorities() {
188         return mTriggeredContentAuthorities;
189     }
190 
191     /**
192      * 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      */
getNetwork()209     public @Nullable Network getNetwork() {
210         return network;
211     }
212 
213     /**
214      * 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      *
221      * <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      *
235      * <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      *
241      * @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      */
dequeueWork()246     public @Nullable JobWorkItem dequeueWork() {
247         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      */
completeWork(@onNull JobWorkItem work)270     public void completeWork(@NonNull JobWorkItem work) {
271         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 
280     /** @hide */
281     @UnsupportedAppUsage
getCallback()282     public IJobCallback getCallback() {
283         return IJobCallback.Stub.asInterface(callback);
284     }
285 
JobParameters(Parcel in)286     private JobParameters(Parcel in) {
287         jobId = in.readInt();
288         extras = in.readPersistableBundle();
289         transientExtras = in.readBundle();
290         if (in.readInt() != 0) {
291             clipData = ClipData.CREATOR.createFromParcel(in);
292             clipGrantFlags = in.readInt();
293         } else {
294             clipData = null;
295             clipGrantFlags = 0;
296         }
297         callback = in.readStrongBinder();
298         overrideDeadlineExpired = in.readInt() == 1;
299         mTriggeredContentUris = in.createTypedArray(Uri.CREATOR);
300         mTriggeredContentAuthorities = in.createStringArray();
301         if (in.readInt() != 0) {
302             network = Network.CREATOR.createFromParcel(in);
303         } else {
304             network = null;
305         }
306         stopReason = in.readInt();
307         debugStopReason = in.readString();
308     }
309 
310     /** @hide */
setStopReason(int reason, String debugStopReason)311     public void setStopReason(int reason, String debugStopReason) {
312         stopReason = reason;
313         this.debugStopReason = debugStopReason;
314     }
315 
316     @Override
describeContents()317     public int describeContents() {
318         return 0;
319     }
320 
321     @Override
writeToParcel(Parcel dest, int flags)322     public void writeToParcel(Parcel dest, int flags) {
323         dest.writeInt(jobId);
324         dest.writePersistableBundle(extras);
325         dest.writeBundle(transientExtras);
326         if (clipData != null) {
327             dest.writeInt(1);
328             clipData.writeToParcel(dest, flags);
329             dest.writeInt(clipGrantFlags);
330         } else {
331             dest.writeInt(0);
332         }
333         dest.writeStrongBinder(callback);
334         dest.writeInt(overrideDeadlineExpired ? 1 : 0);
335         dest.writeTypedArray(mTriggeredContentUris, flags);
336         dest.writeStringArray(mTriggeredContentAuthorities);
337         if (network != null) {
338             dest.writeInt(1);
339             network.writeToParcel(dest, flags);
340         } else {
341             dest.writeInt(0);
342         }
343         dest.writeInt(stopReason);
344         dest.writeString(debugStopReason);
345     }
346 
347     public static final @android.annotation.NonNull Creator<JobParameters> CREATOR = new Creator<JobParameters>() {
348         @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 }
359