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