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.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.TestApi; 23 import android.app.ActivityManager; 24 import android.app.usage.UsageStatsManager; 25 import android.compat.annotation.UnsupportedAppUsage; 26 import android.content.ClipData; 27 import android.content.pm.PackageManager; 28 import android.net.Network; 29 import android.net.NetworkRequest; 30 import android.net.Uri; 31 import android.os.Bundle; 32 import android.os.IBinder; 33 import android.os.Parcel; 34 import android.os.Parcelable; 35 import android.os.PersistableBundle; 36 import android.os.RemoteException; 37 38 import java.lang.annotation.Retention; 39 import java.lang.annotation.RetentionPolicy; 40 41 /** 42 * Contains the parameters used to configure/identify your job. You do not create this object 43 * yourself, instead it is handed in to your application by the System. 44 */ 45 public class JobParameters implements Parcelable { 46 47 /** @hide */ 48 public static final int INTERNAL_STOP_REASON_UNKNOWN = -1; 49 50 /** @hide */ 51 public static final int INTERNAL_STOP_REASON_CANCELED = 52 JobProtoEnums.INTERNAL_STOP_REASON_CANCELLED; // 0. 53 /** @hide */ 54 public static final int INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED = 55 JobProtoEnums.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED; // 1. 56 /** @hide */ 57 public static final int INTERNAL_STOP_REASON_PREEMPT = 58 JobProtoEnums.INTERNAL_STOP_REASON_PREEMPT; // 2. 59 /** 60 * The job ran for at least its minimum execution limit. 61 * @hide 62 */ 63 public static final int INTERNAL_STOP_REASON_TIMEOUT = 64 JobProtoEnums.INTERNAL_STOP_REASON_TIMEOUT; // 3. 65 /** @hide */ 66 public static final int INTERNAL_STOP_REASON_DEVICE_IDLE = 67 JobProtoEnums.INTERNAL_STOP_REASON_DEVICE_IDLE; // 4. 68 /** @hide */ 69 public static final int INTERNAL_STOP_REASON_DEVICE_THERMAL = 70 JobProtoEnums.INTERNAL_STOP_REASON_DEVICE_THERMAL; // 5. 71 /** 72 * The job is in the {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} 73 * bucket. 74 * 75 * @hide 76 */ 77 public static final int INTERNAL_STOP_REASON_RESTRICTED_BUCKET = 78 JobProtoEnums.INTERNAL_STOP_REASON_RESTRICTED_BUCKET; // 6. 79 /** 80 * The app was uninstalled. 81 * @hide 82 */ 83 public static final int INTERNAL_STOP_REASON_UNINSTALL = 84 JobProtoEnums.INTERNAL_STOP_REASON_UNINSTALL; // 7. 85 /** 86 * The app's data was cleared. 87 * @hide 88 */ 89 public static final int INTERNAL_STOP_REASON_DATA_CLEARED = 90 JobProtoEnums.INTERNAL_STOP_REASON_DATA_CLEARED; // 8. 91 /** 92 * @hide 93 */ 94 public static final int INTERNAL_STOP_REASON_RTC_UPDATED = 95 JobProtoEnums.INTERNAL_STOP_REASON_RTC_UPDATED; // 9. 96 /** 97 * The app called jobFinished() on its own. 98 * @hide 99 */ 100 public static final int INTERNAL_STOP_REASON_SUCCESSFUL_FINISH = 101 JobProtoEnums.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH; // 10. 102 /** 103 * The user stopped the job via some UI (eg. Task Manager). 104 * @hide 105 */ 106 @TestApi 107 public static final int INTERNAL_STOP_REASON_USER_UI_STOP = 108 JobProtoEnums.INTERNAL_STOP_REASON_USER_UI_STOP; // 11. 109 /** 110 * The app didn't respond quickly enough from JobScheduler's perspective. 111 * @hide 112 */ 113 public static final int INTERNAL_STOP_REASON_ANR = 114 JobProtoEnums.INTERNAL_STOP_REASON_ANR; // 12. 115 116 /** 117 * All the stop reason codes. This should be regarded as an immutable array at runtime. 118 * 119 * Note the order of these values will affect "dumpsys batterystats", and we do not want to 120 * change the order of existing fields, so adding new fields is okay but do not remove or 121 * change existing fields. When deprecating a field, just replace that with "-1" in this array. 122 * 123 * @hide 124 */ 125 public static final int[] JOB_STOP_REASON_CODES = { 126 INTERNAL_STOP_REASON_UNKNOWN, 127 INTERNAL_STOP_REASON_CANCELED, 128 INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED, 129 INTERNAL_STOP_REASON_PREEMPT, 130 INTERNAL_STOP_REASON_TIMEOUT, 131 INTERNAL_STOP_REASON_DEVICE_IDLE, 132 INTERNAL_STOP_REASON_DEVICE_THERMAL, 133 INTERNAL_STOP_REASON_RESTRICTED_BUCKET, 134 INTERNAL_STOP_REASON_UNINSTALL, 135 INTERNAL_STOP_REASON_DATA_CLEARED, 136 INTERNAL_STOP_REASON_RTC_UPDATED, 137 INTERNAL_STOP_REASON_SUCCESSFUL_FINISH, 138 INTERNAL_STOP_REASON_USER_UI_STOP, 139 INTERNAL_STOP_REASON_ANR, 140 }; 141 142 /** 143 * @hide 144 */ 145 // TODO(142420609): make it @SystemApi for mainline 146 @NonNull getInternalReasonCodeDescription(int reasonCode)147 public static String getInternalReasonCodeDescription(int reasonCode) { 148 switch (reasonCode) { 149 case INTERNAL_STOP_REASON_CANCELED: return "canceled"; 150 case INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED: return "constraints"; 151 case INTERNAL_STOP_REASON_PREEMPT: return "preempt"; 152 case INTERNAL_STOP_REASON_TIMEOUT: return "timeout"; 153 case INTERNAL_STOP_REASON_DEVICE_IDLE: return "device_idle"; 154 case INTERNAL_STOP_REASON_DEVICE_THERMAL: return "thermal"; 155 case INTERNAL_STOP_REASON_RESTRICTED_BUCKET: return "restricted_bucket"; 156 case INTERNAL_STOP_REASON_UNINSTALL: return "uninstall"; 157 case INTERNAL_STOP_REASON_DATA_CLEARED: return "data_cleared"; 158 case INTERNAL_STOP_REASON_RTC_UPDATED: return "rtc_updated"; 159 case INTERNAL_STOP_REASON_SUCCESSFUL_FINISH: return "successful_finish"; 160 case INTERNAL_STOP_REASON_USER_UI_STOP: return "user_ui_stop"; 161 case INTERNAL_STOP_REASON_ANR: return "anr"; 162 default: return "unknown:" + reasonCode; 163 } 164 } 165 166 /** @hide */ 167 @NonNull getJobStopReasonCodes()168 public static int[] getJobStopReasonCodes() { 169 return JOB_STOP_REASON_CODES; 170 } 171 172 /** 173 * There is no reason the job is stopped. This is the value returned from the JobParameters 174 * object passed to {@link JobService#onStartJob(JobParameters)}. 175 */ 176 public static final int STOP_REASON_UNDEFINED = 0; 177 /** 178 * The job was cancelled directly by the app, either by calling 179 * {@link JobScheduler#cancel(int)}, {@link JobScheduler#cancelAll()}, or by scheduling a 180 * new job with the same job ID. 181 */ 182 public static final int STOP_REASON_CANCELLED_BY_APP = 1; 183 /** The job was stopped to run a higher priority job of the app. */ 184 public static final int STOP_REASON_PREEMPT = 2; 185 /** 186 * The job used up its maximum execution time and timed out. Each individual job has a maximum 187 * execution time limit, regardless of how much total quota the app has. See the note on 188 * {@link JobScheduler} and {@link JobInfo} for the execution time limits. 189 */ 190 public static final int STOP_REASON_TIMEOUT = 3; 191 /** 192 * The device state (eg. Doze, battery saver, memory usage, etc) requires JobScheduler stop this 193 * job. 194 */ 195 public static final int STOP_REASON_DEVICE_STATE = 4; 196 /** 197 * The requested battery-not-low constraint is no longer satisfied. 198 * 199 * @see JobInfo.Builder#setRequiresBatteryNotLow(boolean) 200 */ 201 public static final int STOP_REASON_CONSTRAINT_BATTERY_NOT_LOW = 5; 202 /** 203 * The requested charging constraint is no longer satisfied. 204 * 205 * @see JobInfo.Builder#setRequiresCharging(boolean) 206 */ 207 public static final int STOP_REASON_CONSTRAINT_CHARGING = 6; 208 /** 209 * The requested connectivity constraint is no longer satisfied. 210 * 211 * @see JobInfo.Builder#setRequiredNetwork(NetworkRequest) 212 * @see JobInfo.Builder#setRequiredNetworkType(int) 213 */ 214 public static final int STOP_REASON_CONSTRAINT_CONNECTIVITY = 7; 215 /** 216 * The requested idle constraint is no longer satisfied. 217 * 218 * @see JobInfo.Builder#setRequiresDeviceIdle(boolean) 219 */ 220 public static final int STOP_REASON_CONSTRAINT_DEVICE_IDLE = 8; 221 /** 222 * The requested storage-not-low constraint is no longer satisfied. 223 * 224 * @see JobInfo.Builder#setRequiresStorageNotLow(boolean) 225 */ 226 public static final int STOP_REASON_CONSTRAINT_STORAGE_NOT_LOW = 9; 227 /** 228 * The app has consumed all of its current quota. Each app is assigned a quota of how much 229 * it can run jobs within a certain time frame. The quota is informed, in part, by app standby 230 * buckets. Once an app has used up all of its quota, it won't be able to start jobs until 231 * quota is replenished, is changed, or is temporarily not applied. 232 * 233 * @see UsageStatsManager#getAppStandbyBucket() 234 */ 235 public static final int STOP_REASON_QUOTA = 10; 236 /** 237 * The app is restricted from running in the background. 238 * 239 * @see ActivityManager#isBackgroundRestricted() 240 * @see PackageManager#isInstantApp() 241 */ 242 public static final int STOP_REASON_BACKGROUND_RESTRICTION = 11; 243 /** 244 * The current standby bucket requires that the job stop now. 245 * 246 * @see UsageStatsManager#STANDBY_BUCKET_RESTRICTED 247 */ 248 public static final int STOP_REASON_APP_STANDBY = 12; 249 /** 250 * The user stopped the job. This can happen either through force-stop, adb shell commands, 251 * uninstalling, or some other UI. 252 */ 253 public static final int STOP_REASON_USER = 13; 254 /** The system is doing some processing that requires stopping this job. */ 255 public static final int STOP_REASON_SYSTEM_PROCESSING = 14; 256 /** 257 * The system's estimate of when the app will be launched changed significantly enough to 258 * decide this job shouldn't be running right now. This will mostly apply to prefetch jobs. 259 * 260 * @see JobInfo#isPrefetch() 261 * @see JobInfo.Builder#setPrefetch(boolean) 262 */ 263 public static final int STOP_REASON_ESTIMATED_APP_LAUNCH_TIME_CHANGED = 15; 264 265 /** @hide */ 266 @IntDef(prefix = {"STOP_REASON_"}, value = { 267 STOP_REASON_UNDEFINED, 268 STOP_REASON_CANCELLED_BY_APP, 269 STOP_REASON_PREEMPT, 270 STOP_REASON_TIMEOUT, 271 STOP_REASON_DEVICE_STATE, 272 STOP_REASON_CONSTRAINT_BATTERY_NOT_LOW, 273 STOP_REASON_CONSTRAINT_CHARGING, 274 STOP_REASON_CONSTRAINT_CONNECTIVITY, 275 STOP_REASON_CONSTRAINT_DEVICE_IDLE, 276 STOP_REASON_CONSTRAINT_STORAGE_NOT_LOW, 277 STOP_REASON_QUOTA, 278 STOP_REASON_BACKGROUND_RESTRICTION, 279 STOP_REASON_APP_STANDBY, 280 STOP_REASON_USER, 281 STOP_REASON_SYSTEM_PROCESSING, 282 STOP_REASON_ESTIMATED_APP_LAUNCH_TIME_CHANGED, 283 }) 284 @Retention(RetentionPolicy.SOURCE) 285 public @interface StopReason { 286 } 287 288 @UnsupportedAppUsage 289 private final int jobId; 290 @Nullable 291 private final String mJobNamespace; 292 private final PersistableBundle extras; 293 private final Bundle transientExtras; 294 private final ClipData clipData; 295 private final int clipGrantFlags; 296 @UnsupportedAppUsage 297 private final IBinder callback; 298 private final boolean overrideDeadlineExpired; 299 private final boolean mIsExpedited; 300 private final boolean mIsUserInitiated; 301 private final Uri[] mTriggeredContentUris; 302 private final String[] mTriggeredContentAuthorities; 303 @Nullable 304 private Network mNetwork; 305 306 private int mStopReason = STOP_REASON_UNDEFINED; 307 private int mInternalStopReason = INTERNAL_STOP_REASON_UNKNOWN; 308 private String debugStopReason; // Human readable stop reason for debugging. 309 310 /** @hide */ JobParameters(IBinder callback, String namespace, int jobId, PersistableBundle extras, Bundle transientExtras, ClipData clipData, int clipGrantFlags, boolean overrideDeadlineExpired, boolean isExpedited, boolean isUserInitiated, Uri[] triggeredContentUris, String[] triggeredContentAuthorities, Network network)311 public JobParameters(IBinder callback, String namespace, int jobId, PersistableBundle extras, 312 Bundle transientExtras, ClipData clipData, int clipGrantFlags, 313 boolean overrideDeadlineExpired, boolean isExpedited, 314 boolean isUserInitiated, Uri[] triggeredContentUris, 315 String[] triggeredContentAuthorities, Network network) { 316 this.jobId = jobId; 317 this.extras = extras; 318 this.transientExtras = transientExtras; 319 this.clipData = clipData; 320 this.clipGrantFlags = clipGrantFlags; 321 this.callback = callback; 322 this.overrideDeadlineExpired = overrideDeadlineExpired; 323 this.mIsExpedited = isExpedited; 324 this.mIsUserInitiated = isUserInitiated; 325 this.mTriggeredContentUris = triggeredContentUris; 326 this.mTriggeredContentAuthorities = triggeredContentAuthorities; 327 this.mNetwork = network; 328 this.mJobNamespace = namespace; 329 } 330 331 /** 332 * @return The unique id of this job, specified at creation time. 333 */ getJobId()334 public int getJobId() { 335 return jobId; 336 } 337 338 /** 339 * Get the namespace this job was placed in. 340 * 341 * @see JobScheduler#forNamespace(String) 342 * @return The namespace this job was scheduled in. Will be {@code null} if there was no 343 * explicit namespace set and this job is therefore in the default namespace. 344 */ 345 @Nullable getJobNamespace()346 public String getJobNamespace() { 347 return mJobNamespace; 348 } 349 350 /** 351 * @return The reason {@link JobService#onStopJob(JobParameters)} was called on this job. Will 352 * be {@link #STOP_REASON_UNDEFINED} if {@link JobService#onStopJob(JobParameters)} has not 353 * yet been called. 354 */ 355 @StopReason getStopReason()356 public int getStopReason() { 357 return mStopReason; 358 } 359 360 /** @hide */ getInternalStopReasonCode()361 public int getInternalStopReasonCode() { 362 return mInternalStopReason; 363 } 364 365 /** 366 * Reason onStopJob() was called on this job. 367 * 368 * @hide 369 */ getDebugStopReason()370 public String getDebugStopReason() { 371 return debugStopReason; 372 } 373 374 /** 375 * @return The extras you passed in when constructing this job with 376 * {@link android.app.job.JobInfo.Builder#setExtras(android.os.PersistableBundle)}. This will 377 * never be null. If you did not set any extras this will be an empty bundle. 378 */ getExtras()379 public @NonNull PersistableBundle getExtras() { 380 return extras; 381 } 382 383 /** 384 * @return The transient extras you passed in when constructing this job with 385 * {@link android.app.job.JobInfo.Builder#setTransientExtras(android.os.Bundle)}. This will 386 * never be null. If you did not set any extras this will be an empty bundle. 387 */ getTransientExtras()388 public @NonNull Bundle getTransientExtras() { 389 return transientExtras; 390 } 391 392 /** 393 * @return The clip you passed in when constructing this job with 394 * {@link android.app.job.JobInfo.Builder#setClipData(ClipData, int)}. Will be null 395 * if it was not set. 396 */ getClipData()397 public @Nullable ClipData getClipData() { 398 return clipData; 399 } 400 401 /** 402 * @return The clip grant flags you passed in when constructing this job with 403 * {@link android.app.job.JobInfo.Builder#setClipData(ClipData, int)}. Will be 0 404 * if it was not set. 405 */ getClipGrantFlags()406 public int getClipGrantFlags() { 407 return clipGrantFlags; 408 } 409 410 /** 411 * @return Whether this job is running as an expedited job or not. A job is guaranteed to have 412 * all expedited job guarantees for the duration of the job execution if this returns 413 * {@code true}. This will return {@code false} if the job that wasn't requested to run as a 414 * expedited job, or if it was requested to run as an expedited job but the app didn't have 415 * any remaining expedited job quota at the time of execution. 416 * 417 * @see JobInfo.Builder#setExpedited(boolean) 418 */ isExpeditedJob()419 public boolean isExpeditedJob() { 420 return mIsExpedited; 421 } 422 423 /** 424 * @return Whether this job is running as a user-initiated job or not. A job is guaranteed to 425 * have all user-initiated job guarantees for the duration of the job execution if this returns 426 * {@code true}. This will return {@code false} if the job wasn't requested to run as a 427 * user-initiated job, or if it was requested to run as a user-initiated job but the app didn't 428 * meet any of the requirements at the time of execution, such as having the 429 * {@link android.Manifest.permission#RUN_USER_INITIATED_JOBS} permission. 430 * 431 * @see JobInfo.Builder#setUserInitiated(boolean) 432 */ isUserInitiatedJob()433 public boolean isUserInitiatedJob() { 434 return mIsUserInitiated; 435 } 436 437 /** 438 * For jobs with {@link android.app.job.JobInfo.Builder#setOverrideDeadline(long)} set, this 439 * provides an easy way to tell whether the job is being executed due to the deadline 440 * expiring. Note: If the job is running because its deadline expired, it implies that its 441 * constraints will not be met. However, 442 * {@link android.app.job.JobInfo.Builder#setPeriodic(long) periodic jobs} will only ever 443 * run when their constraints are satisfied, therefore, the constraints will still be satisfied 444 * for a periodic job even if the deadline has expired. 445 */ isOverrideDeadlineExpired()446 public boolean isOverrideDeadlineExpired() { 447 return overrideDeadlineExpired; 448 } 449 450 /** 451 * For jobs with {@link android.app.job.JobInfo.Builder#addTriggerContentUri} set, this 452 * reports which URIs have triggered the job. This will be null if either no URIs have 453 * triggered it (it went off due to a deadline or other reason), or the number of changed 454 * URIs is too large to report. Whether or not the number of URIs is too large, you can 455 * always use {@link #getTriggeredContentAuthorities()} to determine whether the job was 456 * triggered due to any content changes and the authorities they are associated with. 457 */ getTriggeredContentUris()458 public @Nullable Uri[] getTriggeredContentUris() { 459 return mTriggeredContentUris; 460 } 461 462 /** 463 * For jobs with {@link android.app.job.JobInfo.Builder#addTriggerContentUri} set, this 464 * reports which content authorities have triggered the job. It will only be null if no 465 * authorities have triggered it -- that is, the job executed for some other reason, such 466 * as a deadline expiring. If this is non-null, you can use {@link #getTriggeredContentUris()} 467 * to retrieve the details of which URIs changed (as long as that has not exceeded the maximum 468 * number it can reported). 469 */ getTriggeredContentAuthorities()470 public @Nullable String[] getTriggeredContentAuthorities() { 471 return mTriggeredContentAuthorities; 472 } 473 474 /** 475 * Return the network that should be used to perform any network requests 476 * for this job. 477 * <p> 478 * Devices may have multiple active network connections simultaneously, or 479 * they may not have a default network route at all. To correctly handle all 480 * situations like this, your job should always use the network returned by 481 * this method instead of implicitly using the default network route. 482 * <p> 483 * Note that the system may relax the constraints you originally requested, 484 * such as allowing a {@link JobInfo#NETWORK_TYPE_UNMETERED} job to run over 485 * a metered network when there is a surplus of metered data available. 486 * 487 * Starting in Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, 488 * this will return {@code null} if the app does not hold the permissions specified in 489 * {@link JobInfo.Builder#setRequiredNetwork(NetworkRequest)}. 490 * 491 * @return the network that should be used to perform any network requests 492 * for this job, or {@code null} if this job didn't set any required 493 * network type or if the job executed when there was no available network to use. 494 * @see JobInfo.Builder#setRequiredNetworkType(int) 495 * @see JobInfo.Builder#setRequiredNetwork(NetworkRequest) 496 */ getNetwork()497 public @Nullable Network getNetwork() { 498 return mNetwork; 499 } 500 501 /** 502 * Dequeue the next pending {@link JobWorkItem} from these JobParameters associated with their 503 * currently running job. Calling this method when there is no more work available and all 504 * previously dequeued work has been completed will result in the system taking care of 505 * stopping the job for you -- 506 * you should not call {@link JobService#jobFinished(JobParameters, boolean)} yourself 507 * (otherwise you risk losing an upcoming JobWorkItem that is being enqueued at the same time). 508 * 509 * <p>Once you are done with the {@link JobWorkItem} returned by this method, you must call 510 * {@link #completeWork(JobWorkItem)} with it to inform the system that you are done 511 * executing the work. The job will not be finished until all dequeued work has been 512 * completed. You do not, however, have to complete each returned work item before deqeueing 513 * the next one -- you can use {@link #dequeueWork()} multiple times before completing 514 * previous work if you want to process work in parallel, and you can complete the work 515 * in whatever order you want.</p> 516 * 517 * <p>If the job runs to the end of its available time period before all work has been 518 * completed, it will stop as normal. You should return true from 519 * {@link JobService#onStopJob(JobParameters)} in order to have the job rescheduled, and by 520 * doing so any pending as well as remaining uncompleted work will be re-queued 521 * for the next time the job runs.</p> 522 * 523 * <p>This example shows how to construct a JobService that will serially dequeue and 524 * process work that is available for it:</p> 525 * 526 * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/JobWorkService.java 527 * service} 528 * 529 * @return Returns a new {@link JobWorkItem} if there is one pending, otherwise null. 530 * If null is returned, the system will also stop the job if all work has also been completed. 531 * (This means that for correct operation, you must always call dequeueWork() after you have 532 * completed other work, to check either for more work or allow the system to stop the job.) 533 */ dequeueWork()534 public @Nullable JobWorkItem dequeueWork() { 535 try { 536 return getCallback().dequeueWork(getJobId()); 537 } catch (RemoteException e) { 538 throw e.rethrowFromSystemServer(); 539 } 540 } 541 542 /** 543 * Report the completion of executing a {@link JobWorkItem} previously returned by 544 * {@link #dequeueWork()}. This tells the system you are done with the 545 * work associated with that item, so it will not be returned again. Note that if this 546 * is the last work in the queue, completing it here will <em>not</em> finish the overall 547 * job -- for that to happen, you still need to call {@link #dequeueWork()} 548 * again. 549 * 550 * <p>If you are enqueueing work into a job, you must call this method for each piece 551 * of work you process. Do <em>not</em> call 552 * {@link JobService#jobFinished(JobParameters, boolean)} 553 * or else you can lose work in your queue.</p> 554 * 555 * @param work The work you have completed processing, as previously returned by 556 * {@link #dequeueWork()} 557 */ completeWork(@onNull JobWorkItem work)558 public void completeWork(@NonNull JobWorkItem work) { 559 try { 560 if (!getCallback().completeWork(getJobId(), work.getWorkId())) { 561 throw new IllegalArgumentException("Given work is not active: " + work); 562 } 563 } catch (RemoteException e) { 564 throw e.rethrowFromSystemServer(); 565 } 566 } 567 568 /** @hide */ 569 @UnsupportedAppUsage getCallback()570 public IJobCallback getCallback() { 571 return IJobCallback.Stub.asInterface(callback); 572 } 573 JobParameters(Parcel in)574 private JobParameters(Parcel in) { 575 jobId = in.readInt(); 576 mJobNamespace = in.readString(); 577 extras = in.readPersistableBundle(); 578 transientExtras = in.readBundle(); 579 if (in.readInt() != 0) { 580 clipData = ClipData.CREATOR.createFromParcel(in); 581 clipGrantFlags = in.readInt(); 582 } else { 583 clipData = null; 584 clipGrantFlags = 0; 585 } 586 callback = in.readStrongBinder(); 587 overrideDeadlineExpired = in.readInt() == 1; 588 mIsExpedited = in.readBoolean(); 589 mIsUserInitiated = in.readBoolean(); 590 mTriggeredContentUris = in.createTypedArray(Uri.CREATOR); 591 mTriggeredContentAuthorities = in.createStringArray(); 592 if (in.readInt() != 0) { 593 mNetwork = Network.CREATOR.createFromParcel(in); 594 } else { 595 mNetwork = null; 596 } 597 mStopReason = in.readInt(); 598 mInternalStopReason = in.readInt(); 599 debugStopReason = in.readString(); 600 } 601 602 /** @hide */ setNetwork(@ullable Network network)603 public void setNetwork(@Nullable Network network) { 604 mNetwork = network; 605 } 606 607 /** @hide */ setStopReason(@topReason int reason, int internalStopReason, String debugStopReason)608 public void setStopReason(@StopReason int reason, int internalStopReason, 609 String debugStopReason) { 610 mStopReason = reason; 611 mInternalStopReason = internalStopReason; 612 this.debugStopReason = debugStopReason; 613 } 614 615 @Override describeContents()616 public int describeContents() { 617 return 0; 618 } 619 620 @Override writeToParcel(Parcel dest, int flags)621 public void writeToParcel(Parcel dest, int flags) { 622 dest.writeInt(jobId); 623 dest.writeString(mJobNamespace); 624 dest.writePersistableBundle(extras); 625 dest.writeBundle(transientExtras); 626 if (clipData != null) { 627 dest.writeInt(1); 628 clipData.writeToParcel(dest, flags); 629 dest.writeInt(clipGrantFlags); 630 } else { 631 dest.writeInt(0); 632 } 633 dest.writeStrongBinder(callback); 634 dest.writeInt(overrideDeadlineExpired ? 1 : 0); 635 dest.writeBoolean(mIsExpedited); 636 dest.writeBoolean(mIsUserInitiated); 637 dest.writeTypedArray(mTriggeredContentUris, flags); 638 dest.writeStringArray(mTriggeredContentAuthorities); 639 if (mNetwork != null) { 640 dest.writeInt(1); 641 mNetwork.writeToParcel(dest, flags); 642 } else { 643 dest.writeInt(0); 644 } 645 dest.writeInt(mStopReason); 646 dest.writeInt(mInternalStopReason); 647 dest.writeString(debugStopReason); 648 } 649 650 public static final @android.annotation.NonNull Creator<JobParameters> CREATOR = new Creator<JobParameters>() { 651 @Override 652 public JobParameters createFromParcel(Parcel in) { 653 return new JobParameters(in); 654 } 655 656 @Override 657 public JobParameters[] newArray(int size) { 658 return new JobParameters[size]; 659 } 660 }; 661 } 662