JobInfo.java revision 075bb7e3f491948d932e7c0096ef4b6ba4ade894
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.annotation.NonNull; 20import android.annotation.Nullable; 21import android.content.ComponentName; 22import android.net.Uri; 23import android.os.Bundle; 24import android.os.Parcel; 25import android.os.Parcelable; 26import android.os.PersistableBundle; 27import android.util.Log; 28import static android.util.TimeUtils.formatForLogging; 29 30import java.util.ArrayList; 31 32/** 33 * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the 34 * parameters required to schedule work against the calling application. These are constructed 35 * using the {@link JobInfo.Builder}. 36 * You must specify at least one sort of constraint on the JobInfo object that you are creating. 37 * The goal here is to provide the scheduler with high-level semantics about the work you want to 38 * accomplish. Doing otherwise with throw an exception in your app. 39 */ 40public class JobInfo implements Parcelable { 41 private static String TAG = "JobInfo"; 42 /** Default. */ 43 public static final int NETWORK_TYPE_NONE = 0; 44 /** This job requires network connectivity. */ 45 public static final int NETWORK_TYPE_ANY = 1; 46 /** This job requires network connectivity that is unmetered. */ 47 public static final int NETWORK_TYPE_UNMETERED = 2; 48 49 /** 50 * Amount of backoff a job has initially by default, in milliseconds. 51 */ 52 public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 30 seconds. 53 54 /** 55 * Maximum backoff we allow for a job, in milliseconds. 56 */ 57 public static final long MAX_BACKOFF_DELAY_MILLIS = 5 * 60 * 60 * 1000; // 5 hours. 58 59 /** 60 * Linearly back-off a failed job. See 61 * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)} 62 * retry_time(current_time, num_failures) = 63 * current_time + initial_backoff_millis * num_failures, num_failures >= 1 64 */ 65 public static final int BACKOFF_POLICY_LINEAR = 0; 66 67 /** 68 * Exponentially back-off a failed job. See 69 * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)} 70 * 71 * retry_time(current_time, num_failures) = 72 * current_time + initial_backoff_millis * 2 ^ (num_failures - 1), num_failures >= 1 73 */ 74 public static final int BACKOFF_POLICY_EXPONENTIAL = 1; 75 76 /* Minimum interval for a periodic job, in milliseconds. */ 77 private static final long MIN_PERIOD_MILLIS = 15 * 60 * 1000L; // 15 minutes 78 79 /* Minimum flex for a periodic job, in milliseconds. */ 80 private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes 81 82 /** 83 * Query the minimum interval allowed for periodic scheduled jobs. Attempting 84 * to declare a smaller period that this when scheduling a job will result in a 85 * job that is still periodic, but will run with this effective period. 86 * 87 * @return The minimum available interval for scheduling periodic jobs, in milliseconds. 88 */ 89 public static final long getMinimumPeriod() { 90 return MIN_PERIOD_MILLIS; 91 } 92 93 /** 94 * Query the minimum flex time allowed for periodic scheduled jobs. Attempting 95 * to declare a shorter flex time than this when scheduling such a job will 96 * result in this amount as the effective flex time for the job. 97 * 98 * @return The minimum available flex time for scheduling periodic jobs, in milliseconds. 99 */ 100 public static final long getMinimumFlex() { 101 return MIN_FLEX_MILLIS; 102 } 103 104 /** 105 * Default type of backoff. 106 * @hide 107 */ 108 public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL; 109 110 /** 111 * Default of {@link #getPriority}. 112 * @hide 113 */ 114 public static final int PRIORITY_DEFAULT = 0; 115 116 /** 117 * Value of {@link #getPriority} for expedited syncs. 118 * @hide 119 */ 120 public static final int PRIORITY_SYNC_EXPEDITED = 10; 121 122 /** 123 * Value of {@link #getPriority} for first time initialization syncs. 124 * @hide 125 */ 126 public static final int PRIORITY_SYNC_INITIALIZATION = 20; 127 128 /** 129 * Value of {@link #getPriority} for a foreground app (overrides the supplied 130 * JobInfo priority if it is smaller). 131 * @hide 132 */ 133 public static final int PRIORITY_FOREGROUND_APP = 30; 134 135 /** 136 * Value of {@link #getPriority} for the current top app (overrides the supplied 137 * JobInfo priority if it is smaller). 138 * @hide 139 */ 140 public static final int PRIORITY_TOP_APP = 40; 141 142 /** 143 * Adjustment of {@link #getPriority} if the app has often (50% or more of the time) 144 * been running jobs. 145 * @hide 146 */ 147 public static final int PRIORITY_ADJ_OFTEN_RUNNING = -40; 148 149 /** 150 * Adjustment of {@link #getPriority} if the app has always (90% or more of the time) 151 * been running jobs. 152 * @hide 153 */ 154 public static final int PRIORITY_ADJ_ALWAYS_RUNNING = -80; 155 156 private final int jobId; 157 private final PersistableBundle extras; 158 private final Bundle transientExtras; 159 private final ComponentName service; 160 private final boolean requireCharging; 161 private final boolean requireDeviceIdle; 162 private final TriggerContentUri[] triggerContentUris; 163 private final long triggerContentUpdateDelay; 164 private final long triggerContentMaxDelay; 165 private final boolean hasEarlyConstraint; 166 private final boolean hasLateConstraint; 167 private final int networkType; 168 private final long minLatencyMillis; 169 private final long maxExecutionDelayMillis; 170 private final boolean isPeriodic; 171 private final boolean isPersisted; 172 private final long intervalMillis; 173 private final long flexMillis; 174 private final long initialBackoffMillis; 175 private final int backoffPolicy; 176 private final int priority; 177 178 /** 179 * Unique job id associated with this class. This is assigned to your job by the scheduler. 180 */ 181 public int getId() { 182 return jobId; 183 } 184 185 /** 186 * Bundle of extras which are returned to your application at execution time. 187 */ 188 public PersistableBundle getExtras() { 189 return extras; 190 } 191 192 /** 193 * Bundle of transient extras which are returned to your application at execution time, 194 * but not persisted by the system. 195 */ 196 public Bundle getTransientExtras() { 197 return transientExtras; 198 } 199 200 /** 201 * Name of the service endpoint that will be called back into by the JobScheduler. 202 */ 203 public ComponentName getService() { 204 return service; 205 } 206 207 /** @hide */ 208 public int getPriority() { 209 return priority; 210 } 211 212 /** 213 * Whether this job needs the device to be plugged in. 214 */ 215 public boolean isRequireCharging() { 216 return requireCharging; 217 } 218 219 /** 220 * Whether this job needs the device to be in an Idle maintenance window. 221 */ 222 public boolean isRequireDeviceIdle() { 223 return requireDeviceIdle; 224 } 225 226 /** 227 * Which content: URIs must change for the job to be scheduled. Returns null 228 * if there are none required. 229 */ 230 @Nullable 231 public TriggerContentUri[] getTriggerContentUris() { 232 return triggerContentUris; 233 } 234 235 /** 236 * When triggering on content URI changes, this is the delay from when a change 237 * is detected until the job is scheduled. 238 */ 239 public long getTriggerContentUpdateDelay() { 240 return triggerContentUpdateDelay; 241 } 242 243 /** 244 * When triggering on content URI changes, this is the maximum delay we will 245 * use before scheduling the job. 246 */ 247 public long getTriggerContentMaxDelay() { 248 return triggerContentMaxDelay; 249 } 250 251 /** 252 * One of {@link android.app.job.JobInfo#NETWORK_TYPE_ANY}, 253 * {@link android.app.job.JobInfo#NETWORK_TYPE_NONE}, or 254 * {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}. 255 */ 256 public int getNetworkType() { 257 return networkType; 258 } 259 260 /** 261 * Set for a job that does not recur periodically, to specify a delay after which the job 262 * will be eligible for execution. This value is not set if the job recurs periodically. 263 */ 264 public long getMinLatencyMillis() { 265 return minLatencyMillis; 266 } 267 268 /** 269 * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the job recurs 270 * periodically. 271 */ 272 public long getMaxExecutionDelayMillis() { 273 return maxExecutionDelayMillis; 274 } 275 276 /** 277 * Track whether this job will repeat with a given period. 278 */ 279 public boolean isPeriodic() { 280 return isPeriodic; 281 } 282 283 /** 284 * @return Whether or not this job should be persisted across device reboots. 285 */ 286 public boolean isPersisted() { 287 return isPersisted; 288 } 289 290 /** 291 * Set to the interval between occurrences of this job. This value is <b>not</b> set if the 292 * job does not recur periodically. 293 */ 294 public long getIntervalMillis() { 295 return intervalMillis >= getMinimumPeriod() ? intervalMillis : getMinimumPeriod(); 296 } 297 298 /** 299 * Flex time for this job. Only valid if this is a periodic job. The job can 300 * execute at any time in a window of flex length at the end of the period. 301 */ 302 public long getFlexMillis() { 303 long interval = getIntervalMillis(); 304 long percentClamp = 5 * interval / 100; 305 long clampedFlex = Math.max(flexMillis, Math.max(percentClamp, getMinimumFlex())); 306 return clampedFlex <= interval ? clampedFlex : interval; 307 } 308 309 /** 310 * The amount of time the JobScheduler will wait before rescheduling a failed job. This value 311 * will be increased depending on the backoff policy specified at job creation time. Defaults 312 * to 5 seconds. 313 */ 314 public long getInitialBackoffMillis() { 315 return initialBackoffMillis; 316 } 317 318 /** 319 * One of either {@link android.app.job.JobInfo#BACKOFF_POLICY_EXPONENTIAL}, or 320 * {@link android.app.job.JobInfo#BACKOFF_POLICY_LINEAR}, depending on which criteria you set 321 * when creating this job. 322 */ 323 public int getBackoffPolicy() { 324 return backoffPolicy; 325 } 326 327 /** 328 * User can specify an early constraint of 0L, which is valid, so we keep track of whether the 329 * function was called at all. 330 * @hide 331 */ 332 public boolean hasEarlyConstraint() { 333 return hasEarlyConstraint; 334 } 335 336 /** 337 * User can specify a late constraint of 0L, which is valid, so we keep track of whether the 338 * function was called at all. 339 * @hide 340 */ 341 public boolean hasLateConstraint() { 342 return hasLateConstraint; 343 } 344 345 private JobInfo(Parcel in) { 346 jobId = in.readInt(); 347 extras = in.readPersistableBundle(); 348 transientExtras = in.readBundle(); 349 service = in.readParcelable(null); 350 requireCharging = in.readInt() == 1; 351 requireDeviceIdle = in.readInt() == 1; 352 triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR); 353 triggerContentUpdateDelay = in.readLong(); 354 triggerContentMaxDelay = in.readLong(); 355 networkType = in.readInt(); 356 minLatencyMillis = in.readLong(); 357 maxExecutionDelayMillis = in.readLong(); 358 isPeriodic = in.readInt() == 1; 359 isPersisted = in.readInt() == 1; 360 intervalMillis = in.readLong(); 361 flexMillis = in.readLong(); 362 initialBackoffMillis = in.readLong(); 363 backoffPolicy = in.readInt(); 364 hasEarlyConstraint = in.readInt() == 1; 365 hasLateConstraint = in.readInt() == 1; 366 priority = in.readInt(); 367 } 368 369 private JobInfo(JobInfo.Builder b) { 370 jobId = b.mJobId; 371 extras = b.mExtras.deepcopy(); 372 transientExtras = b.mTransientExtras.deepcopy(); 373 service = b.mJobService; 374 requireCharging = b.mRequiresCharging; 375 requireDeviceIdle = b.mRequiresDeviceIdle; 376 triggerContentUris = b.mTriggerContentUris != null 377 ? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()]) 378 : null; 379 triggerContentUpdateDelay = b.mTriggerContentUpdateDelay; 380 triggerContentMaxDelay = b.mTriggerContentMaxDelay; 381 networkType = b.mNetworkType; 382 minLatencyMillis = b.mMinLatencyMillis; 383 maxExecutionDelayMillis = b.mMaxExecutionDelayMillis; 384 isPeriodic = b.mIsPeriodic; 385 isPersisted = b.mIsPersisted; 386 intervalMillis = b.mIntervalMillis; 387 flexMillis = b.mFlexMillis; 388 initialBackoffMillis = b.mInitialBackoffMillis; 389 backoffPolicy = b.mBackoffPolicy; 390 hasEarlyConstraint = b.mHasEarlyConstraint; 391 hasLateConstraint = b.mHasLateConstraint; 392 priority = b.mPriority; 393 } 394 395 @Override 396 public int describeContents() { 397 return 0; 398 } 399 400 @Override 401 public void writeToParcel(Parcel out, int flags) { 402 out.writeInt(jobId); 403 out.writePersistableBundle(extras); 404 out.writeBundle(transientExtras); 405 out.writeParcelable(service, flags); 406 out.writeInt(requireCharging ? 1 : 0); 407 out.writeInt(requireDeviceIdle ? 1 : 0); 408 out.writeTypedArray(triggerContentUris, flags); 409 out.writeLong(triggerContentUpdateDelay); 410 out.writeLong(triggerContentMaxDelay); 411 out.writeInt(networkType); 412 out.writeLong(minLatencyMillis); 413 out.writeLong(maxExecutionDelayMillis); 414 out.writeInt(isPeriodic ? 1 : 0); 415 out.writeInt(isPersisted ? 1 : 0); 416 out.writeLong(intervalMillis); 417 out.writeLong(flexMillis); 418 out.writeLong(initialBackoffMillis); 419 out.writeInt(backoffPolicy); 420 out.writeInt(hasEarlyConstraint ? 1 : 0); 421 out.writeInt(hasLateConstraint ? 1 : 0); 422 out.writeInt(priority); 423 } 424 425 public static final Creator<JobInfo> CREATOR = new Creator<JobInfo>() { 426 @Override 427 public JobInfo createFromParcel(Parcel in) { 428 return new JobInfo(in); 429 } 430 431 @Override 432 public JobInfo[] newArray(int size) { 433 return new JobInfo[size]; 434 } 435 }; 436 437 @Override 438 public String toString() { 439 return "(job:" + jobId + "/" + service.flattenToShortString() + ")"; 440 } 441 442 /** 443 * Information about a content URI modification that a job would like to 444 * trigger on. 445 */ 446 public static final class TriggerContentUri implements Parcelable { 447 private final Uri mUri; 448 private final int mFlags; 449 450 /** 451 * Flag for trigger: also trigger if any descendants of the given URI change. 452 * Corresponds to the <var>notifyForDescendants</var> of 453 * {@link android.content.ContentResolver#registerContentObserver}. 454 */ 455 public static final int FLAG_NOTIFY_FOR_DESCENDANTS = 1<<0; 456 457 /** 458 * Create a new trigger description. 459 * @param uri The URI to observe. Must be non-null. 460 * @param flags Optional flags for the observer, either 0 or 461 * {@link #FLAG_NOTIFY_FOR_DESCENDANTS}. 462 */ 463 public TriggerContentUri(@NonNull Uri uri, int flags) { 464 mUri = uri; 465 mFlags = flags; 466 } 467 468 /** 469 * Return the Uri this trigger was created for. 470 */ 471 public Uri getUri() { 472 return mUri; 473 } 474 475 /** 476 * Return the flags supplied for the trigger. 477 */ 478 public int getFlags() { 479 return mFlags; 480 } 481 482 private TriggerContentUri(Parcel in) { 483 mUri = Uri.CREATOR.createFromParcel(in); 484 mFlags = in.readInt(); 485 } 486 487 @Override 488 public int describeContents() { 489 return 0; 490 } 491 492 @Override 493 public void writeToParcel(Parcel out, int flags) { 494 mUri.writeToParcel(out, flags); 495 out.writeInt(mFlags); 496 } 497 498 public static final Creator<TriggerContentUri> CREATOR = new Creator<TriggerContentUri>() { 499 @Override 500 public TriggerContentUri createFromParcel(Parcel in) { 501 return new TriggerContentUri(in); 502 } 503 504 @Override 505 public TriggerContentUri[] newArray(int size) { 506 return new TriggerContentUri[size]; 507 } 508 }; 509 } 510 511 /** Builder class for constructing {@link JobInfo} objects. */ 512 public static final class Builder { 513 private int mJobId; 514 private PersistableBundle mExtras = PersistableBundle.EMPTY; 515 private Bundle mTransientExtras = Bundle.EMPTY; 516 private ComponentName mJobService; 517 private int mPriority = PRIORITY_DEFAULT; 518 // Requirements. 519 private boolean mRequiresCharging; 520 private boolean mRequiresDeviceIdle; 521 private int mNetworkType; 522 private ArrayList<TriggerContentUri> mTriggerContentUris; 523 private long mTriggerContentUpdateDelay = -1; 524 private long mTriggerContentMaxDelay = -1; 525 private boolean mIsPersisted; 526 // One-off parameters. 527 private long mMinLatencyMillis; 528 private long mMaxExecutionDelayMillis; 529 // Periodic parameters. 530 private boolean mIsPeriodic; 531 private boolean mHasEarlyConstraint; 532 private boolean mHasLateConstraint; 533 private long mIntervalMillis; 534 private long mFlexMillis; 535 // Back-off parameters. 536 private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS; 537 private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY; 538 /** Easy way to track whether the client has tried to set a back-off policy. */ 539 private boolean mBackoffPolicySet = false; 540 541 /** 542 * @param jobId Application-provided id for this job. Subsequent calls to cancel, or 543 * jobs created with the same jobId, will update the pre-existing job with 544 * the same id. 545 * @param jobService The endpoint that you implement that will receive the callback from the 546 * JobScheduler. 547 */ 548 public Builder(int jobId, ComponentName jobService) { 549 mJobService = jobService; 550 mJobId = jobId; 551 } 552 553 /** 554 * @hide 555 */ 556 public Builder setPriority(int priority) { 557 mPriority = priority; 558 return this; 559 } 560 561 /** 562 * Set optional extras. This is persisted, so we only allow primitive types. 563 * @param extras Bundle containing extras you want the scheduler to hold on to for you. 564 */ 565 public Builder setExtras(PersistableBundle extras) { 566 mExtras = extras; 567 return this; 568 } 569 570 /** 571 * Set optional transient extras. This is incompatible with jobs that are also 572 * persisted with {@link #setPersisted(boolean)}; mixing the two is not allowed. 573 * @param extras Bundle containing extras you want the scheduler to hold on to for you. 574 */ 575 public Builder setTransientExtras(Bundle extras) { 576 mTransientExtras = extras; 577 return this; 578 } 579 580 /** 581 * Set some description of the kind of network type your job needs to have. 582 * Not calling this function means the network is not necessary, as the default is 583 * {@link #NETWORK_TYPE_NONE}. 584 * Bear in mind that calling this function defines network as a strict requirement for your 585 * job. If the network requested is not available your job will never run. See 586 * {@link #setOverrideDeadline(long)} to change this behaviour. 587 */ 588 public Builder setRequiredNetworkType(int networkType) { 589 mNetworkType = networkType; 590 return this; 591 } 592 593 /** 594 * Specify that to run this job, the device needs to be plugged in. This defaults to 595 * false. 596 * @param requiresCharging Whether or not the device is plugged in. 597 */ 598 public Builder setRequiresCharging(boolean requiresCharging) { 599 mRequiresCharging = requiresCharging; 600 return this; 601 } 602 603 /** 604 * Specify that to run, the job needs the device to be in idle mode. This defaults to 605 * false. 606 * <p>Idle mode is a loose definition provided by the system, which means that the device 607 * is not in use, and has not been in use for some time. As such, it is a good time to 608 * perform resource heavy jobs. Bear in mind that battery usage will still be attributed 609 * to your application, and surfaced to the user in battery stats.</p> 610 * @param requiresDeviceIdle Whether or not the device need be within an idle maintenance 611 * window. 612 */ 613 public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) { 614 mRequiresDeviceIdle = requiresDeviceIdle; 615 return this; 616 } 617 618 /** 619 * Add a new content: URI that will be monitored with a 620 * {@link android.database.ContentObserver}, and will cause the job to execute if changed. 621 * If you have any trigger content URIs associated with a job, it will not execute until 622 * there has been a change report for one or more of them. 623 * <p>Note that trigger URIs can not be used in combination with 624 * {@link #setPeriodic(long)} or {@link #setPersisted(boolean)}. To continually monitor 625 * for content changes, you need to schedule a new JobInfo observing the same URIs 626 * before you finish execution of the JobService handling the most recent changes.</p> 627 * <p>Because because setting this property is not compatible with periodic or 628 * persisted jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when 629 * {@link android.app.job.JobInfo.Builder#build()} is called.</p> 630 * @param uri The content: URI to monitor. 631 */ 632 public Builder addTriggerContentUri(@NonNull TriggerContentUri uri) { 633 if (mTriggerContentUris == null) { 634 mTriggerContentUris = new ArrayList<>(); 635 } 636 mTriggerContentUris.add(uri); 637 return this; 638 } 639 640 /** 641 * Set the delay (in milliseconds) from when a content change is detected until 642 * the job is scheduled. If there are more changes during that time, the delay 643 * will be reset to start at the time of the most recent change. 644 * @param durationMs Delay after most recent content change, in milliseconds. 645 */ 646 public Builder setTriggerContentUpdateDelay(long durationMs) { 647 mTriggerContentUpdateDelay = durationMs; 648 return this; 649 } 650 651 /** 652 * Set the maximum total delay (in milliseconds) that is allowed from the first 653 * time a content change is detected until the job is scheduled. 654 * @param durationMs Delay after initial content change, in milliseconds. 655 */ 656 public Builder setTriggerContentMaxDelay(long durationMs) { 657 mTriggerContentMaxDelay = durationMs; 658 return this; 659 } 660 661 /** 662 * Specify that this job should recur with the provided interval, not more than once per 663 * period. You have no control over when within this interval this job will be executed, 664 * only the guarantee that it will be executed at most once within this interval. 665 * Setting this function on the builder with {@link #setMinimumLatency(long)} or 666 * {@link #setOverrideDeadline(long)} will result in an error. 667 * @param intervalMillis Millisecond interval for which this job will repeat. 668 */ 669 public Builder setPeriodic(long intervalMillis) { 670 return setPeriodic(intervalMillis, intervalMillis); 671 } 672 673 /** 674 * Specify that this job should recur with the provided interval and flex. The job can 675 * execute at any time in a window of flex length at the end of the period. 676 * @param intervalMillis Millisecond interval for which this job will repeat. A minimum 677 * value of {@link #getMinimumPeriod()} is enforced. 678 * @param flexMillis Millisecond flex for this job. Flex is clamped to be at least 679 * {@link #getMinimumFlex()} or 5 percent of the period, whichever is 680 * higher. 681 */ 682 public Builder setPeriodic(long intervalMillis, long flexMillis) { 683 mIsPeriodic = true; 684 mIntervalMillis = intervalMillis; 685 mFlexMillis = flexMillis; 686 mHasEarlyConstraint = mHasLateConstraint = true; 687 return this; 688 } 689 690 /** 691 * Specify that this job should be delayed by the provided amount of time. 692 * Because it doesn't make sense setting this property on a periodic job, doing so will 693 * throw an {@link java.lang.IllegalArgumentException} when 694 * {@link android.app.job.JobInfo.Builder#build()} is called. 695 * @param minLatencyMillis Milliseconds before which this job will not be considered for 696 * execution. 697 */ 698 public Builder setMinimumLatency(long minLatencyMillis) { 699 mMinLatencyMillis = minLatencyMillis; 700 mHasEarlyConstraint = true; 701 return this; 702 } 703 704 /** 705 * Set deadline which is the maximum scheduling latency. The job will be run by this 706 * deadline even if other requirements are not met. Because it doesn't make sense setting 707 * this property on a periodic job, doing so will throw an 708 * {@link java.lang.IllegalArgumentException} when 709 * {@link android.app.job.JobInfo.Builder#build()} is called. 710 */ 711 public Builder setOverrideDeadline(long maxExecutionDelayMillis) { 712 mMaxExecutionDelayMillis = maxExecutionDelayMillis; 713 mHasLateConstraint = true; 714 return this; 715 } 716 717 /** 718 * Set up the back-off/retry policy. 719 * This defaults to some respectable values: {30 seconds, Exponential}. We cap back-off at 720 * 5hrs. 721 * Note that trying to set a backoff criteria for a job with 722 * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build(). 723 * This is because back-off typically does not make sense for these types of jobs. See 724 * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)} 725 * for more description of the return value for the case of a job executing while in idle 726 * mode. 727 * @param initialBackoffMillis Millisecond time interval to wait initially when job has 728 * failed. 729 * @param backoffPolicy is one of {@link #BACKOFF_POLICY_LINEAR} or 730 * {@link #BACKOFF_POLICY_EXPONENTIAL} 731 */ 732 public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) { 733 mBackoffPolicySet = true; 734 mInitialBackoffMillis = initialBackoffMillis; 735 mBackoffPolicy = backoffPolicy; 736 return this; 737 } 738 739 /** 740 * Set whether or not to persist this job across device reboots. This will only have an 741 * effect if your application holds the permission 742 * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED}. Otherwise an exception will 743 * be thrown. 744 * @param isPersisted True to indicate that the job will be written to disk and loaded at 745 * boot. 746 */ 747 public Builder setPersisted(boolean isPersisted) { 748 mIsPersisted = isPersisted; 749 return this; 750 } 751 752 /** 753 * @return The job object to hand to the JobScheduler. This object is immutable. 754 */ 755 public JobInfo build() { 756 // Allow jobs with no constraints - What am I, a database? 757 if (!mHasEarlyConstraint && !mHasLateConstraint && !mRequiresCharging && 758 !mRequiresDeviceIdle && mNetworkType == NETWORK_TYPE_NONE && 759 mTriggerContentUris == null) { 760 throw new IllegalArgumentException("You're trying to build a job with no " + 761 "constraints, this is not allowed."); 762 } 763 // Check that a deadline was not set on a periodic job. 764 if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) { 765 throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " + 766 "periodic job."); 767 } 768 if (mIsPeriodic && (mMinLatencyMillis != 0L)) { 769 throw new IllegalArgumentException("Can't call setMinimumLatency() on a " + 770 "periodic job"); 771 } 772 if (mIsPeriodic && (mTriggerContentUris != null)) { 773 throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " + 774 "periodic job"); 775 } 776 if (mIsPersisted && (mTriggerContentUris != null)) { 777 throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " + 778 "persisted job"); 779 } 780 if (mIsPersisted && !mTransientExtras.isEmpty()) { 781 throw new IllegalArgumentException("Can't call setTransientExtras() on a " + 782 "persisted job"); 783 } 784 if (mBackoffPolicySet && mRequiresDeviceIdle) { 785 throw new IllegalArgumentException("An idle mode job will not respect any" + 786 " back-off policy, so calling setBackoffCriteria with" + 787 " setRequiresDeviceIdle is an error."); 788 } 789 JobInfo job = new JobInfo(this); 790 if (job.intervalMillis != job.getIntervalMillis()) { 791 Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is " 792 + formatForLogging(mIntervalMillis) + ". Clamped to " + 793 formatForLogging(job.getIntervalMillis())); 794 } 795 if (job.flexMillis != job.getFlexMillis()) { 796 Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is " 797 + formatForLogging(mFlexMillis) + ". Clamped to " + 798 formatForLogging(job.getFlexMillis())); 799 } 800 return job; 801 } 802 } 803 804} 805