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