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 static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; 20 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; 21 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; 22 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; 23 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; 24 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; 25 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 26 import static android.util.TimeUtils.formatDuration; 27 28 import android.annotation.BytesLong; 29 import android.annotation.IntDef; 30 import android.annotation.NonNull; 31 import android.annotation.Nullable; 32 import android.annotation.RequiresPermission; 33 import android.compat.Compatibility; 34 import android.compat.annotation.ChangeId; 35 import android.compat.annotation.EnabledSince; 36 import android.compat.annotation.UnsupportedAppUsage; 37 import android.content.ClipData; 38 import android.content.ComponentName; 39 import android.net.NetworkRequest; 40 import android.net.NetworkSpecifier; 41 import android.net.Uri; 42 import android.os.BaseBundle; 43 import android.os.Build; 44 import android.os.Bundle; 45 import android.os.Parcel; 46 import android.os.Parcelable; 47 import android.os.PersistableBundle; 48 import android.util.Log; 49 50 import java.lang.annotation.Retention; 51 import java.lang.annotation.RetentionPolicy; 52 import java.util.ArrayList; 53 import java.util.Arrays; 54 import java.util.Objects; 55 56 /** 57 * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the 58 * parameters required to schedule work against the calling application. These are constructed 59 * using the {@link JobInfo.Builder}. 60 * The goal here is to provide the scheduler with high-level semantics about the work you want to 61 * accomplish. 62 * <p> Prior to Android version {@link Build.VERSION_CODES#Q}, you had to specify at least one 63 * constraint on the JobInfo object that you are creating. Otherwise, the builder would throw an 64 * exception when building. From Android version {@link Build.VERSION_CODES#Q} and onwards, it is 65 * valid to schedule jobs with no constraints. 66 */ 67 public class JobInfo implements Parcelable { 68 private static String TAG = "JobInfo"; 69 70 /** 71 * Disallow setting a deadline (via {@link Builder#setOverrideDeadline(long)}) for prefetch 72 * jobs ({@link Builder#setPrefetch(boolean)}. Prefetch jobs are meant to run close to the next 73 * app launch, so there's no good reason to allow them to have deadlines. 74 * 75 * We don't drop or cancel any previously scheduled prefetch jobs with a deadline. 76 * There's no way for an app to keep a perpetually scheduled prefetch job with a deadline. 77 * Prefetch jobs with a deadline will run and apps under this restriction won't be able to 78 * schedule new prefetch jobs with a deadline. If a job is rescheduled (by providing 79 * {@code true} via {@link JobService#jobFinished(JobParameters, boolean)} or 80 * {@link JobService#onStopJob(JobParameters)}'s return value),the deadline is dropped. 81 * Periodic jobs require all constraints to be met, so there's no issue with their deadlines. 82 * 83 * @hide 84 */ 85 @ChangeId 86 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) 87 public static final long DISALLOW_DEADLINES_FOR_PREFETCH_JOBS = 194532703L; 88 89 /** 90 * Whether to throw an exception when an app provides an invalid priority value via 91 * {@link Builder#setPriority(int)}. Legacy apps may be incorrectly using the API and 92 * so the call will silently fail for them if they continue using the API. 93 * 94 * @hide 95 */ 96 @ChangeId 97 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) 98 public static final long THROW_ON_INVALID_PRIORITY_VALUE = 140852299L; 99 100 /** @hide */ 101 @IntDef(prefix = { "NETWORK_TYPE_" }, value = { 102 NETWORK_TYPE_NONE, 103 NETWORK_TYPE_ANY, 104 NETWORK_TYPE_UNMETERED, 105 NETWORK_TYPE_NOT_ROAMING, 106 NETWORK_TYPE_CELLULAR, 107 }) 108 @Retention(RetentionPolicy.SOURCE) 109 public @interface NetworkType {} 110 111 /** Default. */ 112 public static final int NETWORK_TYPE_NONE = 0; 113 /** This job requires network connectivity. */ 114 public static final int NETWORK_TYPE_ANY = 1; 115 /** This job requires network connectivity that is unmetered. */ 116 public static final int NETWORK_TYPE_UNMETERED = 2; 117 /** This job requires network connectivity that is not roaming. */ 118 public static final int NETWORK_TYPE_NOT_ROAMING = 3; 119 /** This job requires network connectivity that is a cellular network. */ 120 public static final int NETWORK_TYPE_CELLULAR = 4; 121 122 /** 123 * This job requires metered connectivity such as most cellular data 124 * networks. 125 * 126 * @deprecated Cellular networks may be unmetered, or Wi-Fi networks may be 127 * metered, so this isn't a good way of selecting a specific 128 * transport. Instead, use {@link #NETWORK_TYPE_CELLULAR} or 129 * {@link android.net.NetworkRequest.Builder#addTransportType(int)} 130 * if your job requires a specific network transport. 131 */ 132 @Deprecated 133 public static final int NETWORK_TYPE_METERED = NETWORK_TYPE_CELLULAR; 134 135 /** Sentinel value indicating that bytes are unknown. */ 136 public static final int NETWORK_BYTES_UNKNOWN = -1; 137 138 /** 139 * Amount of backoff a job has initially by default, in milliseconds. 140 */ 141 public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 30 seconds. 142 143 /** 144 * Maximum backoff we allow for a job, in milliseconds. 145 */ 146 public static final long MAX_BACKOFF_DELAY_MILLIS = 5 * 60 * 60 * 1000; // 5 hours. 147 148 /** @hide */ 149 @IntDef(prefix = { "BACKOFF_POLICY_" }, value = { 150 BACKOFF_POLICY_LINEAR, 151 BACKOFF_POLICY_EXPONENTIAL, 152 }) 153 @Retention(RetentionPolicy.SOURCE) 154 public @interface BackoffPolicy {} 155 156 /** 157 * Linearly back-off a failed job. See 158 * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)} 159 * retry_time(current_time, num_failures) = 160 * current_time + initial_backoff_millis * num_failures, num_failures >= 1 161 */ 162 public static final int BACKOFF_POLICY_LINEAR = 0; 163 164 /** 165 * Exponentially back-off a failed job. See 166 * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)} 167 * 168 * retry_time(current_time, num_failures) = 169 * current_time + initial_backoff_millis * 2 ^ (num_failures - 1), num_failures >= 1 170 */ 171 public static final int BACKOFF_POLICY_EXPONENTIAL = 1; 172 173 /* Minimum interval for a periodic job, in milliseconds. */ 174 private static final long MIN_PERIOD_MILLIS = 15 * 60 * 1000L; // 15 minutes 175 176 /* Minimum flex for a periodic job, in milliseconds. */ 177 private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes 178 179 /** 180 * Minimum backoff interval for a job, in milliseconds 181 * @hide 182 */ 183 public static final long MIN_BACKOFF_MILLIS = 10 * 1000L; // 10 seconds 184 185 /** 186 * Query the minimum interval allowed for periodic scheduled jobs. Attempting 187 * to declare a smaller period than this when scheduling a job will result in a 188 * job that is still periodic, but will run with this effective period. 189 * 190 * @return The minimum available interval for scheduling periodic jobs, in milliseconds. 191 */ getMinPeriodMillis()192 public static final long getMinPeriodMillis() { 193 return MIN_PERIOD_MILLIS; 194 } 195 196 /** 197 * Query the minimum flex time allowed for periodic scheduled jobs. Attempting 198 * to declare a shorter flex time than this when scheduling such a job will 199 * result in this amount as the effective flex time for the job. 200 * 201 * @return The minimum available flex time for scheduling periodic jobs, in milliseconds. 202 */ getMinFlexMillis()203 public static final long getMinFlexMillis() { 204 return MIN_FLEX_MILLIS; 205 } 206 207 /** 208 * Query the minimum automatic-reschedule backoff interval permitted for jobs. 209 * @hide 210 */ getMinBackoffMillis()211 public static final long getMinBackoffMillis() { 212 return MIN_BACKOFF_MILLIS; 213 } 214 215 /** 216 * Default type of backoff. 217 * @hide 218 */ 219 public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL; 220 221 /** 222 * Job has minimal value to the user. The user has absolutely no expectation 223 * or knowledge of this task and it has no bearing on the user's perception of 224 * the app whatsoever. JobScheduler <i>may</i> decide to defer these tasks while 225 * there are higher priority tasks in order to ensure there is sufficient quota 226 * available for the higher priority tasks. 227 * A sample task of min priority: uploading analytics 228 */ 229 public static final int PRIORITY_MIN = 100; 230 231 /** 232 * Low priority. The task provides some benefit to users, but is not critical 233 * and is more of a nice-to-have. This is more important than minimum priority 234 * jobs and will be prioritized ahead of them, but may still be deferred in lieu 235 * of higher priority jobs. JobScheduler <i>may</i> decide to defer these tasks 236 * while there are higher priority tasks in order to ensure there is sufficient 237 * quota available for the higher priority tasks. 238 * A sample task of low priority: prefetching data the user hasn't requested 239 */ 240 public static final int PRIORITY_LOW = 200; 241 242 /** 243 * Default value for all regular jobs. As noted in {@link JobScheduler}, 244 * these jobs have a general execution time of 10 minutes. 245 * Receives the standard job management policy. 246 */ 247 public static final int PRIORITY_DEFAULT = 300; 248 249 /** 250 * This task should be ordered ahead of most other tasks. It may be 251 * deferred a little, but if it doesn't run at some point, the user may think 252 * something is wrong. Assuming all constraints remain satisfied 253 * (including ideal system load conditions), these jobs can have an 254 * execution time of at least 4 minutes. Setting all of your jobs to high 255 * priority will not be beneficial to your app and in fact may hurt its 256 * performance in the long run. 257 */ 258 public static final int PRIORITY_HIGH = 400; 259 260 /** 261 * This task should be run ahead of all other tasks. Only Expedited Jobs 262 * {@link Builder#setExpedited(boolean)} can have this priority and as such, 263 * are subject to the same execution time details noted in 264 * {@link Builder#setExpedited(boolean)}. 265 * A sample task of max priority: receiving a text message and processing it to 266 * show a notification 267 */ 268 public static final int PRIORITY_MAX = 500; 269 270 /** @hide */ 271 @IntDef(prefix = {"PRIORITY_"}, value = { 272 PRIORITY_MIN, 273 PRIORITY_LOW, 274 PRIORITY_DEFAULT, 275 PRIORITY_HIGH, 276 PRIORITY_MAX, 277 }) 278 @Retention(RetentionPolicy.SOURCE) 279 public @interface Priority { 280 } 281 282 /** 283 * Default of {@link #getBias}. 284 * @hide 285 */ 286 public static final int BIAS_DEFAULT = 0; 287 288 /** 289 * Value of {@link #getBias} for expedited syncs. 290 * @hide 291 */ 292 public static final int BIAS_SYNC_EXPEDITED = 10; 293 294 /** 295 * Value of {@link #getBias} for first time initialization syncs. 296 * @hide 297 */ 298 public static final int BIAS_SYNC_INITIALIZATION = 20; 299 300 /** 301 * Value of {@link #getBias} for a BFGS app (overrides the supplied 302 * JobInfo bias if it is smaller). 303 * @hide 304 */ 305 public static final int BIAS_BOUND_FOREGROUND_SERVICE = 30; 306 307 /** @hide For backward compatibility. */ 308 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 309 public static final int PRIORITY_FOREGROUND_APP = BIAS_BOUND_FOREGROUND_SERVICE; 310 311 /** 312 * Value of {@link #getBias} for a FG service app (overrides the supplied 313 * JobInfo bias if it is smaller). 314 * @hide 315 */ 316 public static final int BIAS_FOREGROUND_SERVICE = 35; 317 318 /** @hide For backward compatibility. */ 319 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 320 public static final int PRIORITY_FOREGROUND_SERVICE = BIAS_FOREGROUND_SERVICE; 321 322 /** 323 * Value of {@link #getBias} for the current top app (overrides the supplied 324 * JobInfo bias if it is smaller). 325 * @hide 326 */ 327 public static final int BIAS_TOP_APP = 40; 328 329 /** 330 * Adjustment of {@link #getBias} if the app has often (50% or more of the time) 331 * been running jobs. 332 * @hide 333 */ 334 public static final int BIAS_ADJ_OFTEN_RUNNING = -40; 335 336 /** 337 * Adjustment of {@link #getBias} if the app has always (90% or more of the time) 338 * been running jobs. 339 * @hide 340 */ 341 public static final int BIAS_ADJ_ALWAYS_RUNNING = -80; 342 343 /** 344 * Indicates that the implementation of this job will be using 345 * {@link JobService#startForeground(int, android.app.Notification)} to run 346 * in the foreground. 347 * <p> 348 * When set, the internal scheduling of this job will ignore any background 349 * network restrictions for the requesting app. Note that this flag alone 350 * doesn't actually place your {@link JobService} in the foreground; you 351 * still need to post the notification yourself. 352 * <p> 353 * To use this flag, the caller must hold the 354 * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL} permission. 355 * 356 * @hide 357 */ 358 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 359 public static final int FLAG_WILL_BE_FOREGROUND = 1 << 0; 360 361 /** 362 * Allows this job to run despite doze restrictions as long as the app is in the foreground 363 * or on the temporary whitelist 364 * @hide 365 */ 366 public static final int FLAG_IMPORTANT_WHILE_FOREGROUND = 1 << 1; 367 368 /** 369 * @hide 370 */ 371 public static final int FLAG_PREFETCH = 1 << 2; 372 373 /** 374 * This job needs to be exempted from the app standby throttling. Only the system (UID 1000) 375 * can set it. Jobs with a time constraint must not have it. 376 * 377 * @hide 378 */ 379 public static final int FLAG_EXEMPT_FROM_APP_STANDBY = 1 << 3; 380 381 /** 382 * Whether it's an expedited job or not. 383 * 384 * @hide 385 */ 386 public static final int FLAG_EXPEDITED = 1 << 4; 387 388 /** 389 * @hide 390 */ 391 public static final int CONSTRAINT_FLAG_CHARGING = 1 << 0; 392 393 /** 394 * @hide 395 */ 396 public static final int CONSTRAINT_FLAG_BATTERY_NOT_LOW = 1 << 1; 397 398 /** 399 * @hide 400 */ 401 public static final int CONSTRAINT_FLAG_DEVICE_IDLE = 1 << 2; 402 403 /** 404 * @hide 405 */ 406 public static final int CONSTRAINT_FLAG_STORAGE_NOT_LOW = 1 << 3; 407 408 @UnsupportedAppUsage 409 private final int jobId; 410 private final PersistableBundle extras; 411 private final Bundle transientExtras; 412 private final ClipData clipData; 413 private final int clipGrantFlags; 414 @UnsupportedAppUsage 415 private final ComponentName service; 416 private final int constraintFlags; 417 private final TriggerContentUri[] triggerContentUris; 418 private final long triggerContentUpdateDelay; 419 private final long triggerContentMaxDelay; 420 private final boolean hasEarlyConstraint; 421 private final boolean hasLateConstraint; 422 private final NetworkRequest networkRequest; 423 private final long networkDownloadBytes; 424 private final long networkUploadBytes; 425 private final long minimumNetworkChunkBytes; 426 private final long minLatencyMillis; 427 private final long maxExecutionDelayMillis; 428 private final boolean isPeriodic; 429 private final boolean isPersisted; 430 private final long intervalMillis; 431 private final long flexMillis; 432 private final long initialBackoffMillis; 433 private final int backoffPolicy; 434 private final int mBias; 435 @Priority 436 private final int mPriority; 437 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 438 private final int flags; 439 440 /** 441 * Unique job id associated with this application (uid). This is the same job ID 442 * you supplied in the {@link Builder} constructor. 443 */ getId()444 public int getId() { 445 return jobId; 446 } 447 448 /** 449 * @see JobInfo.Builder#setExtras(PersistableBundle) 450 */ getExtras()451 public @NonNull PersistableBundle getExtras() { 452 return extras; 453 } 454 455 /** 456 * @see JobInfo.Builder#setTransientExtras(Bundle) 457 */ getTransientExtras()458 public @NonNull Bundle getTransientExtras() { 459 return transientExtras; 460 } 461 462 /** 463 * @see JobInfo.Builder#setClipData(ClipData, int) 464 */ getClipData()465 public @Nullable ClipData getClipData() { 466 return clipData; 467 } 468 469 /** 470 * @see JobInfo.Builder#setClipData(ClipData, int) 471 */ getClipGrantFlags()472 public int getClipGrantFlags() { 473 return clipGrantFlags; 474 } 475 476 /** 477 * Name of the service endpoint that will be called back into by the JobScheduler. 478 */ getService()479 public @NonNull ComponentName getService() { 480 return service; 481 } 482 483 /** @hide */ getBias()484 public int getBias() { 485 return mBias; 486 } 487 488 /** 489 * @see JobInfo.Builder#setPriority(int) 490 */ 491 @Priority getPriority()492 public int getPriority() { 493 return mPriority; 494 } 495 496 /** @hide */ getFlags()497 public int getFlags() { 498 return flags; 499 } 500 501 /** @hide */ isExemptedFromAppStandby()502 public boolean isExemptedFromAppStandby() { 503 return ((flags & FLAG_EXEMPT_FROM_APP_STANDBY) != 0) && !isPeriodic(); 504 } 505 506 /** 507 * @see JobInfo.Builder#setRequiresCharging(boolean) 508 */ isRequireCharging()509 public boolean isRequireCharging() { 510 return (constraintFlags & CONSTRAINT_FLAG_CHARGING) != 0; 511 } 512 513 /** 514 * @see JobInfo.Builder#setRequiresBatteryNotLow(boolean) 515 */ isRequireBatteryNotLow()516 public boolean isRequireBatteryNotLow() { 517 return (constraintFlags & CONSTRAINT_FLAG_BATTERY_NOT_LOW) != 0; 518 } 519 520 /** 521 * @see JobInfo.Builder#setRequiresDeviceIdle(boolean) 522 */ isRequireDeviceIdle()523 public boolean isRequireDeviceIdle() { 524 return (constraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0; 525 } 526 527 /** 528 * @see JobInfo.Builder#setRequiresStorageNotLow(boolean) 529 */ isRequireStorageNotLow()530 public boolean isRequireStorageNotLow() { 531 return (constraintFlags & CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0; 532 } 533 534 /** 535 * @hide 536 */ getConstraintFlags()537 public int getConstraintFlags() { 538 return constraintFlags; 539 } 540 541 /** 542 * Which content: URIs must change for the job to be scheduled. Returns null 543 * if there are none required. 544 * @see JobInfo.Builder#addTriggerContentUri(TriggerContentUri) 545 */ getTriggerContentUris()546 public @Nullable TriggerContentUri[] getTriggerContentUris() { 547 return triggerContentUris; 548 } 549 550 /** 551 * When triggering on content URI changes, this is the delay from when a change 552 * is detected until the job is scheduled. 553 * @see JobInfo.Builder#setTriggerContentUpdateDelay(long) 554 */ getTriggerContentUpdateDelay()555 public long getTriggerContentUpdateDelay() { 556 return triggerContentUpdateDelay; 557 } 558 559 /** 560 * When triggering on content URI changes, this is the maximum delay we will 561 * use before scheduling the job. 562 * @see JobInfo.Builder#setTriggerContentMaxDelay(long) 563 */ getTriggerContentMaxDelay()564 public long getTriggerContentMaxDelay() { 565 return triggerContentMaxDelay; 566 } 567 568 /** 569 * Return the basic description of the kind of network this job requires. 570 * 571 * @deprecated This method attempts to map {@link #getRequiredNetwork()} 572 * into the set of simple constants, which results in a loss of 573 * fidelity. Callers should move to using 574 * {@link #getRequiredNetwork()} directly. 575 * @see Builder#setRequiredNetworkType(int) 576 */ 577 @Deprecated getNetworkType()578 public @NetworkType int getNetworkType() { 579 if (networkRequest == null) { 580 return NETWORK_TYPE_NONE; 581 } else if (networkRequest.hasCapability(NET_CAPABILITY_NOT_METERED)) { 582 return NETWORK_TYPE_UNMETERED; 583 } else if (networkRequest.hasCapability(NET_CAPABILITY_NOT_ROAMING)) { 584 return NETWORK_TYPE_NOT_ROAMING; 585 } else if (networkRequest.hasTransport(TRANSPORT_CELLULAR)) { 586 return NETWORK_TYPE_CELLULAR; 587 } else { 588 return NETWORK_TYPE_ANY; 589 } 590 } 591 592 /** 593 * Return the detailed description of the kind of network this job requires, 594 * or {@code null} if no specific kind of network is required. 595 * 596 * @see Builder#setRequiredNetwork(NetworkRequest) 597 */ getRequiredNetwork()598 public @Nullable NetworkRequest getRequiredNetwork() { 599 return networkRequest; 600 } 601 602 /** 603 * Return the estimated size of download traffic that will be performed by 604 * this job, in bytes. 605 * 606 * @return Estimated size of download traffic, or 607 * {@link #NETWORK_BYTES_UNKNOWN} when unknown. 608 * @see Builder#setEstimatedNetworkBytes(long, long) 609 */ getEstimatedNetworkDownloadBytes()610 public @BytesLong long getEstimatedNetworkDownloadBytes() { 611 return networkDownloadBytes; 612 } 613 614 /** 615 * Return the estimated size of upload traffic that will be performed by 616 * this job, in bytes. 617 * 618 * @return Estimated size of upload traffic, or 619 * {@link #NETWORK_BYTES_UNKNOWN} when unknown. 620 * @see Builder#setEstimatedNetworkBytes(long, long) 621 */ getEstimatedNetworkUploadBytes()622 public @BytesLong long getEstimatedNetworkUploadBytes() { 623 return networkUploadBytes; 624 } 625 626 /** 627 * Return the smallest piece of data that cannot be easily paused and resumed, in bytes. 628 * 629 * @return Smallest piece of data that cannot be easily paused and resumed, or 630 * {@link #NETWORK_BYTES_UNKNOWN} when unknown. 631 * @see Builder#setMinimumNetworkChunkBytes(long) 632 */ getMinimumNetworkChunkBytes()633 public @BytesLong long getMinimumNetworkChunkBytes() { 634 return minimumNetworkChunkBytes; 635 } 636 637 /** 638 * Set for a job that does not recur periodically, to specify a delay after which the job 639 * will be eligible for execution. This value is not set if the job recurs periodically. 640 * @see JobInfo.Builder#setMinimumLatency(long) 641 */ getMinLatencyMillis()642 public long getMinLatencyMillis() { 643 return minLatencyMillis; 644 } 645 646 /** 647 * @see JobInfo.Builder#setOverrideDeadline(long) 648 */ getMaxExecutionDelayMillis()649 public long getMaxExecutionDelayMillis() { 650 return maxExecutionDelayMillis; 651 } 652 653 /** 654 * Track whether this job will repeat with a given period. 655 * @see JobInfo.Builder#setPeriodic(long) 656 * @see JobInfo.Builder#setPeriodic(long, long) 657 */ isPeriodic()658 public boolean isPeriodic() { 659 return isPeriodic; 660 } 661 662 /** 663 * @see JobInfo.Builder#setPersisted(boolean) 664 */ isPersisted()665 public boolean isPersisted() { 666 return isPersisted; 667 } 668 669 /** 670 * Set to the interval between occurrences of this job. This value is <b>not</b> set if the 671 * job does not recur periodically. 672 * @see JobInfo.Builder#setPeriodic(long) 673 * @see JobInfo.Builder#setPeriodic(long, long) 674 */ getIntervalMillis()675 public long getIntervalMillis() { 676 return intervalMillis; 677 } 678 679 /** 680 * Flex time for this job. Only valid if this is a periodic job. The job can 681 * execute at any time in a window of flex length at the end of the period. 682 * @see JobInfo.Builder#setPeriodic(long) 683 * @see JobInfo.Builder#setPeriodic(long, long) 684 */ getFlexMillis()685 public long getFlexMillis() { 686 return flexMillis; 687 } 688 689 /** 690 * The amount of time the JobScheduler will wait before rescheduling a failed job. This value 691 * will be increased depending on the backoff policy specified at job creation time. Defaults 692 * to 30 seconds, minimum is currently 10 seconds. 693 * @see JobInfo.Builder#setBackoffCriteria(long, int) 694 */ getInitialBackoffMillis()695 public long getInitialBackoffMillis() { 696 return initialBackoffMillis; 697 } 698 699 /** 700 * Return the backoff policy of this job. 701 * 702 * @see JobInfo.Builder#setBackoffCriteria(long, int) 703 */ getBackoffPolicy()704 public @BackoffPolicy int getBackoffPolicy() { 705 return backoffPolicy; 706 } 707 708 /** 709 * @see JobInfo.Builder#setExpedited(boolean) 710 */ isExpedited()711 public boolean isExpedited() { 712 return (flags & FLAG_EXPEDITED) != 0; 713 } 714 715 /** 716 * @see JobInfo.Builder#setImportantWhileForeground(boolean) 717 */ isImportantWhileForeground()718 public boolean isImportantWhileForeground() { 719 return (flags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0; 720 } 721 722 /** 723 * @see JobInfo.Builder#setPrefetch(boolean) 724 */ isPrefetch()725 public boolean isPrefetch() { 726 return (flags & FLAG_PREFETCH) != 0; 727 } 728 729 /** 730 * User can specify an early constraint of 0L, which is valid, so we keep track of whether the 731 * function was called at all. 732 * @hide 733 */ hasEarlyConstraint()734 public boolean hasEarlyConstraint() { 735 return hasEarlyConstraint; 736 } 737 738 /** 739 * User can specify a late constraint of 0L, which is valid, so we keep track of whether the 740 * function was called at all. 741 * @hide 742 */ hasLateConstraint()743 public boolean hasLateConstraint() { 744 return hasLateConstraint; 745 } 746 747 @Override equals(Object o)748 public boolean equals(Object o) { 749 if (!(o instanceof JobInfo)) { 750 return false; 751 } 752 JobInfo j = (JobInfo) o; 753 if (jobId != j.jobId) { 754 return false; 755 } 756 // XXX won't be correct if one is parcelled and the other not. 757 if (!BaseBundle.kindofEquals(extras, j.extras)) { 758 return false; 759 } 760 // XXX won't be correct if one is parcelled and the other not. 761 if (!BaseBundle.kindofEquals(transientExtras, j.transientExtras)) { 762 return false; 763 } 764 // XXX for now we consider two different clip data objects to be different, 765 // regardless of whether their contents are the same. 766 if (clipData != j.clipData) { 767 return false; 768 } 769 if (clipGrantFlags != j.clipGrantFlags) { 770 return false; 771 } 772 if (!Objects.equals(service, j.service)) { 773 return false; 774 } 775 if (constraintFlags != j.constraintFlags) { 776 return false; 777 } 778 if (!Arrays.equals(triggerContentUris, j.triggerContentUris)) { 779 return false; 780 } 781 if (triggerContentUpdateDelay != j.triggerContentUpdateDelay) { 782 return false; 783 } 784 if (triggerContentMaxDelay != j.triggerContentMaxDelay) { 785 return false; 786 } 787 if (hasEarlyConstraint != j.hasEarlyConstraint) { 788 return false; 789 } 790 if (hasLateConstraint != j.hasLateConstraint) { 791 return false; 792 } 793 if (!Objects.equals(networkRequest, j.networkRequest)) { 794 return false; 795 } 796 if (networkDownloadBytes != j.networkDownloadBytes) { 797 return false; 798 } 799 if (networkUploadBytes != j.networkUploadBytes) { 800 return false; 801 } 802 if (minimumNetworkChunkBytes != j.minimumNetworkChunkBytes) { 803 return false; 804 } 805 if (minLatencyMillis != j.minLatencyMillis) { 806 return false; 807 } 808 if (maxExecutionDelayMillis != j.maxExecutionDelayMillis) { 809 return false; 810 } 811 if (isPeriodic != j.isPeriodic) { 812 return false; 813 } 814 if (isPersisted != j.isPersisted) { 815 return false; 816 } 817 if (intervalMillis != j.intervalMillis) { 818 return false; 819 } 820 if (flexMillis != j.flexMillis) { 821 return false; 822 } 823 if (initialBackoffMillis != j.initialBackoffMillis) { 824 return false; 825 } 826 if (backoffPolicy != j.backoffPolicy) { 827 return false; 828 } 829 if (mBias != j.mBias) { 830 return false; 831 } 832 if (mPriority != j.mPriority) { 833 return false; 834 } 835 if (flags != j.flags) { 836 return false; 837 } 838 return true; 839 } 840 841 @Override hashCode()842 public int hashCode() { 843 int hashCode = jobId; 844 if (extras != null) { 845 hashCode = 31 * hashCode + extras.hashCode(); 846 } 847 if (transientExtras != null) { 848 hashCode = 31 * hashCode + transientExtras.hashCode(); 849 } 850 if (clipData != null) { 851 hashCode = 31 * hashCode + clipData.hashCode(); 852 } 853 hashCode = 31*hashCode + clipGrantFlags; 854 if (service != null) { 855 hashCode = 31 * hashCode + service.hashCode(); 856 } 857 hashCode = 31 * hashCode + constraintFlags; 858 if (triggerContentUris != null) { 859 hashCode = 31 * hashCode + Arrays.hashCode(triggerContentUris); 860 } 861 hashCode = 31 * hashCode + Long.hashCode(triggerContentUpdateDelay); 862 hashCode = 31 * hashCode + Long.hashCode(triggerContentMaxDelay); 863 hashCode = 31 * hashCode + Boolean.hashCode(hasEarlyConstraint); 864 hashCode = 31 * hashCode + Boolean.hashCode(hasLateConstraint); 865 if (networkRequest != null) { 866 hashCode = 31 * hashCode + networkRequest.hashCode(); 867 } 868 hashCode = 31 * hashCode + Long.hashCode(networkDownloadBytes); 869 hashCode = 31 * hashCode + Long.hashCode(networkUploadBytes); 870 hashCode = 31 * hashCode + Long.hashCode(minimumNetworkChunkBytes); 871 hashCode = 31 * hashCode + Long.hashCode(minLatencyMillis); 872 hashCode = 31 * hashCode + Long.hashCode(maxExecutionDelayMillis); 873 hashCode = 31 * hashCode + Boolean.hashCode(isPeriodic); 874 hashCode = 31 * hashCode + Boolean.hashCode(isPersisted); 875 hashCode = 31 * hashCode + Long.hashCode(intervalMillis); 876 hashCode = 31 * hashCode + Long.hashCode(flexMillis); 877 hashCode = 31 * hashCode + Long.hashCode(initialBackoffMillis); 878 hashCode = 31 * hashCode + backoffPolicy; 879 hashCode = 31 * hashCode + mBias; 880 hashCode = 31 * hashCode + mPriority; 881 hashCode = 31 * hashCode + flags; 882 return hashCode; 883 } 884 885 @SuppressWarnings("UnsafeParcelApi") JobInfo(Parcel in)886 private JobInfo(Parcel in) { 887 jobId = in.readInt(); 888 extras = in.readPersistableBundle(); 889 transientExtras = in.readBundle(); 890 if (in.readInt() != 0) { 891 clipData = ClipData.CREATOR.createFromParcel(in); 892 clipGrantFlags = in.readInt(); 893 } else { 894 clipData = null; 895 clipGrantFlags = 0; 896 } 897 service = in.readParcelable(null); 898 constraintFlags = in.readInt(); 899 triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR); 900 triggerContentUpdateDelay = in.readLong(); 901 triggerContentMaxDelay = in.readLong(); 902 if (in.readInt() != 0) { 903 networkRequest = NetworkRequest.CREATOR.createFromParcel(in); 904 } else { 905 networkRequest = null; 906 } 907 networkDownloadBytes = in.readLong(); 908 networkUploadBytes = in.readLong(); 909 minimumNetworkChunkBytes = in.readLong(); 910 minLatencyMillis = in.readLong(); 911 maxExecutionDelayMillis = in.readLong(); 912 isPeriodic = in.readInt() == 1; 913 isPersisted = in.readInt() == 1; 914 intervalMillis = in.readLong(); 915 flexMillis = in.readLong(); 916 initialBackoffMillis = in.readLong(); 917 backoffPolicy = in.readInt(); 918 hasEarlyConstraint = in.readInt() == 1; 919 hasLateConstraint = in.readInt() == 1; 920 mBias = in.readInt(); 921 mPriority = in.readInt(); 922 flags = in.readInt(); 923 } 924 JobInfo(JobInfo.Builder b)925 private JobInfo(JobInfo.Builder b) { 926 jobId = b.mJobId; 927 extras = b.mExtras.deepCopy(); 928 transientExtras = b.mTransientExtras.deepCopy(); 929 clipData = b.mClipData; 930 clipGrantFlags = b.mClipGrantFlags; 931 service = b.mJobService; 932 constraintFlags = b.mConstraintFlags; 933 triggerContentUris = b.mTriggerContentUris != null 934 ? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()]) 935 : null; 936 triggerContentUpdateDelay = b.mTriggerContentUpdateDelay; 937 triggerContentMaxDelay = b.mTriggerContentMaxDelay; 938 networkRequest = b.mNetworkRequest; 939 networkDownloadBytes = b.mNetworkDownloadBytes; 940 networkUploadBytes = b.mNetworkUploadBytes; 941 minimumNetworkChunkBytes = b.mMinimumNetworkChunkBytes; 942 minLatencyMillis = b.mMinLatencyMillis; 943 maxExecutionDelayMillis = b.mMaxExecutionDelayMillis; 944 isPeriodic = b.mIsPeriodic; 945 isPersisted = b.mIsPersisted; 946 intervalMillis = b.mIntervalMillis; 947 flexMillis = b.mFlexMillis; 948 initialBackoffMillis = b.mInitialBackoffMillis; 949 backoffPolicy = b.mBackoffPolicy; 950 hasEarlyConstraint = b.mHasEarlyConstraint; 951 hasLateConstraint = b.mHasLateConstraint; 952 mBias = b.mBias; 953 mPriority = b.mPriority; 954 flags = b.mFlags; 955 } 956 957 @Override describeContents()958 public int describeContents() { 959 return 0; 960 } 961 962 @Override writeToParcel(Parcel out, int flags)963 public void writeToParcel(Parcel out, int flags) { 964 out.writeInt(jobId); 965 out.writePersistableBundle(extras); 966 out.writeBundle(transientExtras); 967 if (clipData != null) { 968 out.writeInt(1); 969 clipData.writeToParcel(out, flags); 970 out.writeInt(clipGrantFlags); 971 } else { 972 out.writeInt(0); 973 } 974 out.writeParcelable(service, flags); 975 out.writeInt(constraintFlags); 976 out.writeTypedArray(triggerContentUris, flags); 977 out.writeLong(triggerContentUpdateDelay); 978 out.writeLong(triggerContentMaxDelay); 979 if (networkRequest != null) { 980 out.writeInt(1); 981 networkRequest.writeToParcel(out, flags); 982 } else { 983 out.writeInt(0); 984 } 985 out.writeLong(networkDownloadBytes); 986 out.writeLong(networkUploadBytes); 987 out.writeLong(minimumNetworkChunkBytes); 988 out.writeLong(minLatencyMillis); 989 out.writeLong(maxExecutionDelayMillis); 990 out.writeInt(isPeriodic ? 1 : 0); 991 out.writeInt(isPersisted ? 1 : 0); 992 out.writeLong(intervalMillis); 993 out.writeLong(flexMillis); 994 out.writeLong(initialBackoffMillis); 995 out.writeInt(backoffPolicy); 996 out.writeInt(hasEarlyConstraint ? 1 : 0); 997 out.writeInt(hasLateConstraint ? 1 : 0); 998 out.writeInt(mBias); 999 out.writeInt(mPriority); 1000 out.writeInt(this.flags); 1001 } 1002 1003 public static final @android.annotation.NonNull Creator<JobInfo> CREATOR = new Creator<JobInfo>() { 1004 @Override 1005 public JobInfo createFromParcel(Parcel in) { 1006 return new JobInfo(in); 1007 } 1008 1009 @Override 1010 public JobInfo[] newArray(int size) { 1011 return new JobInfo[size]; 1012 } 1013 }; 1014 1015 @Override toString()1016 public String toString() { 1017 return "(job:" + jobId + "/" + service.flattenToShortString() + ")"; 1018 } 1019 1020 /** 1021 * Information about a content URI modification that a job would like to 1022 * trigger on. 1023 */ 1024 public static final class TriggerContentUri implements Parcelable { 1025 private final Uri mUri; 1026 private final int mFlags; 1027 1028 /** @hide */ 1029 @Retention(RetentionPolicy.SOURCE) 1030 @IntDef(flag = true, prefix = { "FLAG_" }, value = { 1031 FLAG_NOTIFY_FOR_DESCENDANTS, 1032 }) 1033 public @interface Flags { } 1034 1035 /** 1036 * Flag for trigger: also trigger if any descendants of the given URI change. 1037 * Corresponds to the <var>notifyForDescendants</var> of 1038 * {@link android.content.ContentResolver#registerContentObserver}. 1039 */ 1040 public static final int FLAG_NOTIFY_FOR_DESCENDANTS = 1<<0; 1041 1042 /** 1043 * Create a new trigger description. 1044 * @param uri The URI to observe. Must be non-null. 1045 * @param flags Flags for the observer. 1046 */ TriggerContentUri(@onNull Uri uri, @Flags int flags)1047 public TriggerContentUri(@NonNull Uri uri, @Flags int flags) { 1048 mUri = Objects.requireNonNull(uri); 1049 mFlags = flags; 1050 } 1051 1052 /** 1053 * Return the Uri this trigger was created for. 1054 */ getUri()1055 public Uri getUri() { 1056 return mUri; 1057 } 1058 1059 /** 1060 * Return the flags supplied for the trigger. 1061 */ getFlags()1062 public @Flags int getFlags() { 1063 return mFlags; 1064 } 1065 1066 @Override equals(Object o)1067 public boolean equals(Object o) { 1068 if (!(o instanceof TriggerContentUri)) { 1069 return false; 1070 } 1071 TriggerContentUri t = (TriggerContentUri) o; 1072 return Objects.equals(t.mUri, mUri) && t.mFlags == mFlags; 1073 } 1074 1075 @Override hashCode()1076 public int hashCode() { 1077 return (mUri == null ? 0 : mUri.hashCode()) ^ mFlags; 1078 } 1079 TriggerContentUri(Parcel in)1080 private TriggerContentUri(Parcel in) { 1081 mUri = Uri.CREATOR.createFromParcel(in); 1082 mFlags = in.readInt(); 1083 } 1084 1085 @Override describeContents()1086 public int describeContents() { 1087 return 0; 1088 } 1089 1090 @Override writeToParcel(Parcel out, int flags)1091 public void writeToParcel(Parcel out, int flags) { 1092 mUri.writeToParcel(out, flags); 1093 out.writeInt(mFlags); 1094 } 1095 1096 public static final @android.annotation.NonNull Creator<TriggerContentUri> CREATOR = new Creator<TriggerContentUri>() { 1097 @Override 1098 public TriggerContentUri createFromParcel(Parcel in) { 1099 return new TriggerContentUri(in); 1100 } 1101 1102 @Override 1103 public TriggerContentUri[] newArray(int size) { 1104 return new TriggerContentUri[size]; 1105 } 1106 }; 1107 } 1108 1109 /** Builder class for constructing {@link JobInfo} objects. */ 1110 public static final class Builder { 1111 private final int mJobId; 1112 private final ComponentName mJobService; 1113 private PersistableBundle mExtras = PersistableBundle.EMPTY; 1114 private Bundle mTransientExtras = Bundle.EMPTY; 1115 private ClipData mClipData; 1116 private int mClipGrantFlags; 1117 private int mBias = BIAS_DEFAULT; 1118 @Priority 1119 private int mPriority = PRIORITY_DEFAULT; 1120 private int mFlags; 1121 // Requirements. 1122 private int mConstraintFlags; 1123 private NetworkRequest mNetworkRequest; 1124 private long mNetworkDownloadBytes = NETWORK_BYTES_UNKNOWN; 1125 private long mNetworkUploadBytes = NETWORK_BYTES_UNKNOWN; 1126 private long mMinimumNetworkChunkBytes = NETWORK_BYTES_UNKNOWN; 1127 private ArrayList<TriggerContentUri> mTriggerContentUris; 1128 private long mTriggerContentUpdateDelay = -1; 1129 private long mTriggerContentMaxDelay = -1; 1130 private boolean mIsPersisted; 1131 // One-off parameters. 1132 private long mMinLatencyMillis; 1133 private long mMaxExecutionDelayMillis; 1134 // Periodic parameters. 1135 private boolean mIsPeriodic; 1136 private boolean mHasEarlyConstraint; 1137 private boolean mHasLateConstraint; 1138 private long mIntervalMillis; 1139 private long mFlexMillis; 1140 // Back-off parameters. 1141 private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS; 1142 private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY; 1143 /** Easy way to track whether the client has tried to set a back-off policy. */ 1144 private boolean mBackoffPolicySet = false; 1145 1146 /** 1147 * Initialize a new Builder to construct a {@link JobInfo}. 1148 * 1149 * @param jobId Application-provided id for this job. Subsequent calls to cancel, or 1150 * jobs created with the same jobId, will update the pre-existing job with 1151 * the same id. This ID must be unique across all clients of the same uid 1152 * (not just the same package). You will want to make sure this is a stable 1153 * id across app updates, so probably not based on a resource ID. 1154 * @param jobService The endpoint that you implement that will receive the callback from the 1155 * JobScheduler. 1156 */ Builder(int jobId, @NonNull ComponentName jobService)1157 public Builder(int jobId, @NonNull ComponentName jobService) { 1158 mJobService = jobService; 1159 mJobId = jobId; 1160 } 1161 1162 /** 1163 * Creates a new Builder of JobInfo from an existing instance. 1164 * @hide 1165 */ Builder(@onNull JobInfo job)1166 public Builder(@NonNull JobInfo job) { 1167 mJobId = job.getId(); 1168 mJobService = job.getService(); 1169 mExtras = job.getExtras(); 1170 mTransientExtras = job.getTransientExtras(); 1171 mClipData = job.getClipData(); 1172 mClipGrantFlags = job.getClipGrantFlags(); 1173 mBias = job.getBias(); 1174 mFlags = job.getFlags(); 1175 mConstraintFlags = job.getConstraintFlags(); 1176 mNetworkRequest = job.getRequiredNetwork(); 1177 mNetworkDownloadBytes = job.getEstimatedNetworkDownloadBytes(); 1178 mNetworkUploadBytes = job.getEstimatedNetworkUploadBytes(); 1179 mMinimumNetworkChunkBytes = job.getMinimumNetworkChunkBytes(); 1180 mTriggerContentUris = job.getTriggerContentUris() != null 1181 ? new ArrayList<>(Arrays.asList(job.getTriggerContentUris())) : null; 1182 mTriggerContentUpdateDelay = job.getTriggerContentUpdateDelay(); 1183 mTriggerContentMaxDelay = job.getTriggerContentMaxDelay(); 1184 mIsPersisted = job.isPersisted(); 1185 mMinLatencyMillis = job.getMinLatencyMillis(); 1186 mMaxExecutionDelayMillis = job.getMaxExecutionDelayMillis(); 1187 mIsPeriodic = job.isPeriodic(); 1188 mHasEarlyConstraint = job.hasEarlyConstraint(); 1189 mHasLateConstraint = job.hasLateConstraint(); 1190 mIntervalMillis = job.getIntervalMillis(); 1191 mFlexMillis = job.getFlexMillis(); 1192 mInitialBackoffMillis = job.getInitialBackoffMillis(); 1193 // mBackoffPolicySet isn't set but it's fine since this is copying from an already valid 1194 // job. 1195 mBackoffPolicy = job.getBackoffPolicy(); 1196 mPriority = job.getPriority(); 1197 } 1198 1199 /** @hide */ 1200 @NonNull setBias(int bias)1201 public Builder setBias(int bias) { 1202 mBias = bias; 1203 return this; 1204 } 1205 1206 /** 1207 * Indicate the priority for this job. The priority set here will be used to sort jobs 1208 * for the calling app and apply slightly different policies based on the priority. 1209 * The priority will <b>NOT</b> be used as a global sorting value to sort between 1210 * different app's jobs. Use this to inform the system about which jobs it should try 1211 * to run before other jobs. Giving the same priority to all of your jobs will result 1212 * in them all being treated the same. The priorities each have slightly different 1213 * behaviors, as noted in their relevant javadoc. 1214 * 1215 * <b>NOTE:</b> Setting all of your jobs to high priority will not be 1216 * beneficial to your app and in fact may hurt its performance in the 1217 * long run. 1218 * 1219 * In order to prevent starvation, repeatedly retried jobs (because of failures) will slowly 1220 * have their priorities lowered. 1221 * 1222 * @see JobInfo#getPriority() 1223 */ 1224 @NonNull setPriority(@riority int priority)1225 public Builder setPriority(@Priority int priority) { 1226 if (priority > PRIORITY_MAX || priority < PRIORITY_MIN) { 1227 if (Compatibility.isChangeEnabled(THROW_ON_INVALID_PRIORITY_VALUE)) { 1228 throw new IllegalArgumentException("Invalid priority value"); 1229 } 1230 // No-op for invalid calls of apps that are targeting S-. This was an unsupported 1231 // API before Tiramisu, so anyone calling this that isn't targeting T isn't 1232 // guaranteed a behavior change. 1233 return this; 1234 } 1235 mPriority = priority; 1236 return this; 1237 } 1238 1239 /** @hide */ 1240 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setFlags(int flags)1241 public Builder setFlags(int flags) { 1242 mFlags = flags; 1243 return this; 1244 } 1245 1246 /** 1247 * Set optional extras. This is persisted, so we only allow primitive types. 1248 * @param extras Bundle containing extras you want the scheduler to hold on to for you. 1249 * @see JobInfo#getExtras() 1250 */ setExtras(@onNull PersistableBundle extras)1251 public Builder setExtras(@NonNull PersistableBundle extras) { 1252 mExtras = extras; 1253 return this; 1254 } 1255 1256 /** 1257 * Set optional transient extras. 1258 * 1259 * <p>Because setting this property is not compatible with persisted 1260 * jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when 1261 * {@link android.app.job.JobInfo.Builder#build()} is called.</p> 1262 * 1263 * @param extras Bundle containing extras you want the scheduler to hold on to for you. 1264 * @see JobInfo#getTransientExtras() 1265 */ setTransientExtras(@onNull Bundle extras)1266 public Builder setTransientExtras(@NonNull Bundle extras) { 1267 mTransientExtras = extras; 1268 return this; 1269 } 1270 1271 /** 1272 * Set a {@link ClipData} associated with this Job. 1273 * 1274 * <p>The main purpose of providing a ClipData is to allow granting of 1275 * URI permissions for data associated with the clip. The exact kind 1276 * of permission grant to perform is specified through <var>grantFlags</var>. 1277 * 1278 * <p>If the ClipData contains items that are Intents, any 1279 * grant flags in those Intents will be ignored. Only flags provided as an argument 1280 * to this method are respected, and will be applied to all Uri or 1281 * Intent items in the clip (or sub-items of the clip). 1282 * 1283 * <p>Because setting this property is not compatible with persisted 1284 * jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when 1285 * {@link android.app.job.JobInfo.Builder#build()} is called.</p> 1286 * 1287 * @param clip The new clip to set. May be null to clear the current clip. 1288 * @param grantFlags The desired permissions to grant for any URIs. This should be 1289 * a combination of {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}, 1290 * {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, and 1291 * {@link android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION}. 1292 * @see JobInfo#getClipData() 1293 * @see JobInfo#getClipGrantFlags() 1294 */ setClipData(@ullable ClipData clip, int grantFlags)1295 public Builder setClipData(@Nullable ClipData clip, int grantFlags) { 1296 mClipData = clip; 1297 mClipGrantFlags = grantFlags; 1298 return this; 1299 } 1300 1301 /** 1302 * Set basic description of the kind of network your job requires. If 1303 * you need more precise control over network capabilities, see 1304 * {@link #setRequiredNetwork(NetworkRequest)}. 1305 * <p> 1306 * If your job doesn't need a network connection, you don't need to call 1307 * this method, as the default value is {@link #NETWORK_TYPE_NONE}. 1308 * <p> 1309 * Calling this method defines network as a strict requirement for your 1310 * job. If the network requested is not available your job will never 1311 * run. See {@link #setOverrideDeadline(long)} to change this behavior. 1312 * Calling this method will override any requirements previously defined 1313 * by {@link #setRequiredNetwork(NetworkRequest)}; you typically only 1314 * want to call one of these methods. 1315 * <p class="note"> 1316 * When your job executes in 1317 * {@link JobService#onStartJob(JobParameters)}, be sure to use the 1318 * specific network returned by {@link JobParameters#getNetwork()}, 1319 * otherwise you'll use the default network which may not meet this 1320 * constraint. 1321 * 1322 * @see #setRequiredNetwork(NetworkRequest) 1323 * @see JobInfo#getNetworkType() 1324 * @see JobParameters#getNetwork() 1325 */ setRequiredNetworkType(@etworkType int networkType)1326 public Builder setRequiredNetworkType(@NetworkType int networkType) { 1327 if (networkType == NETWORK_TYPE_NONE) { 1328 return setRequiredNetwork(null); 1329 } else { 1330 final NetworkRequest.Builder builder = new NetworkRequest.Builder(); 1331 1332 // All types require validated Internet 1333 builder.addCapability(NET_CAPABILITY_INTERNET); 1334 builder.addCapability(NET_CAPABILITY_VALIDATED); 1335 builder.removeCapability(NET_CAPABILITY_NOT_VPN); 1336 builder.removeCapability(NET_CAPABILITY_NOT_RESTRICTED); 1337 1338 if (networkType == NETWORK_TYPE_ANY) { 1339 // No other capabilities 1340 } else if (networkType == NETWORK_TYPE_UNMETERED) { 1341 builder.addCapability(NET_CAPABILITY_NOT_METERED); 1342 } else if (networkType == NETWORK_TYPE_NOT_ROAMING) { 1343 builder.addCapability(NET_CAPABILITY_NOT_ROAMING); 1344 } else if (networkType == NETWORK_TYPE_CELLULAR) { 1345 builder.addTransportType(TRANSPORT_CELLULAR); 1346 } 1347 1348 return setRequiredNetwork(builder.build()); 1349 } 1350 } 1351 1352 /** 1353 * Set detailed description of the kind of network your job requires. 1354 * <p> 1355 * If your job doesn't need a network connection, you don't need to call 1356 * this method, as the default is {@code null}. 1357 * <p> 1358 * Calling this method defines network as a strict requirement for your 1359 * job. If the network requested is not available your job will never 1360 * run. See {@link #setOverrideDeadline(long)} to change this behavior. 1361 * Calling this method will override any requirements previously defined 1362 * by {@link #setRequiredNetworkType(int)}; you typically only want to 1363 * call one of these methods. 1364 * <p class="note"> 1365 * When your job executes in 1366 * {@link JobService#onStartJob(JobParameters)}, be sure to use the 1367 * specific network returned by {@link JobParameters#getNetwork()}, 1368 * otherwise you'll use the default network which may not meet this 1369 * constraint. 1370 * 1371 * @param networkRequest The detailed description of the kind of network 1372 * this job requires, or {@code null} if no specific kind of 1373 * network is required. Defining a {@link NetworkSpecifier} 1374 * is only supported for jobs that aren't persisted. 1375 * @see #setRequiredNetworkType(int) 1376 * @see JobInfo#getRequiredNetwork() 1377 * @see JobParameters#getNetwork() 1378 */ setRequiredNetwork(@ullable NetworkRequest networkRequest)1379 public Builder setRequiredNetwork(@Nullable NetworkRequest networkRequest) { 1380 mNetworkRequest = networkRequest; 1381 return this; 1382 } 1383 1384 /** 1385 * Set the estimated size of network traffic that will be performed by 1386 * this job, in bytes. 1387 * <p> 1388 * Apps are encouraged to provide values that are as accurate as 1389 * possible, but when the exact size isn't available, an 1390 * order-of-magnitude estimate can be provided instead. Here are some 1391 * specific examples: 1392 * <ul> 1393 * <li>A job that is backing up a photo knows the exact size of that 1394 * photo, so it should provide that size as the estimate. 1395 * <li>A job that refreshes top news stories wouldn't know an exact 1396 * size, but if the size is expected to be consistently around 100KB, it 1397 * can provide that order-of-magnitude value as the estimate. 1398 * <li>A job that synchronizes email could end up using an extreme range 1399 * of data, from under 1KB when nothing has changed, to dozens of MB 1400 * when there are new emails with attachments. Jobs that cannot provide 1401 * reasonable estimates should use the sentinel value 1402 * {@link JobInfo#NETWORK_BYTES_UNKNOWN}. 1403 * </ul> 1404 * Note that the system may choose to delay jobs with large network 1405 * usage estimates when the device has a poor network connection, in 1406 * order to save battery and possible network costs. 1407 * Starting from Android version {@link Build.VERSION_CODES#S}, JobScheduler may attempt 1408 * to run large jobs when the device is charging and on an unmetered network, even if the 1409 * network is slow. This gives large jobs an opportunity to make forward progress, even if 1410 * they risk timing out. 1411 * <p> 1412 * The values provided here only reflect the traffic that will be 1413 * performed by the base job; if you're using {@link JobWorkItem} then 1414 * you also need to define the network traffic used by each work item 1415 * when constructing them. 1416 * 1417 * <p class="note"> 1418 * Prior to Android version {@link Build.VERSION_CODES#TIRAMISU}, JobScheduler used the 1419 * estimated transfer numbers in a similar fashion to 1420 * {@link #setMinimumNetworkChunkBytes(long)} (to estimate if the work would complete 1421 * within the time available to job). In other words, JobScheduler treated the transfer as 1422 * all-or-nothing. Starting from Android version {@link Build.VERSION_CODES#TIRAMISU}, 1423 * JobScheduler will only use the estimated transfer numbers in this manner if minimum 1424 * chunk sizes have not been provided via {@link #setMinimumNetworkChunkBytes(long)}. 1425 * 1426 * @param downloadBytes The estimated size of network traffic that will 1427 * be downloaded by this job, in bytes. 1428 * @param uploadBytes The estimated size of network traffic that will be 1429 * uploaded by this job, in bytes. 1430 * @see JobInfo#getEstimatedNetworkDownloadBytes() 1431 * @see JobInfo#getEstimatedNetworkUploadBytes() 1432 * @see JobWorkItem#JobWorkItem(android.content.Intent, long, long) 1433 */ setEstimatedNetworkBytes(@ytesLong long downloadBytes, @BytesLong long uploadBytes)1434 public Builder setEstimatedNetworkBytes(@BytesLong long downloadBytes, 1435 @BytesLong long uploadBytes) { 1436 mNetworkDownloadBytes = downloadBytes; 1437 mNetworkUploadBytes = uploadBytes; 1438 return this; 1439 } 1440 1441 /** 1442 * Set the minimum size of non-resumable network traffic this job requires, in bytes. When 1443 * the upload or download can be easily paused and resumed, use this to set the smallest 1444 * size that must be transmitted between start and stop events to be considered successful. 1445 * If the transfer cannot be paused and resumed, then this should be the sum of the values 1446 * provided to {@link JobInfo.Builder#setEstimatedNetworkBytes(long, long)}. 1447 * 1448 * <p> 1449 * Apps are encouraged to provide values that are as accurate as possible since JobScheduler 1450 * will try to run the job at a time when at least the minimum chunk can be transmitted to 1451 * reduce the amount of repetitive data that's transferred. Jobs that cannot provide 1452 * reasonable estimates should use the sentinel value {@link JobInfo#NETWORK_BYTES_UNKNOWN}. 1453 * 1454 * <p> 1455 * The values provided here only reflect the minimum non-resumable traffic that will be 1456 * performed by the base job; if you're using {@link JobWorkItem} then 1457 * you also need to define the network traffic used by each work item 1458 * when constructing them. 1459 * 1460 * @param chunkSizeBytes The smallest piece of data that cannot be easily paused and 1461 * resumed, in bytes. 1462 * @see JobInfo#getMinimumNetworkChunkBytes() 1463 * @see JobWorkItem#JobWorkItem(android.content.Intent, long, long, long) 1464 */ 1465 @NonNull setMinimumNetworkChunkBytes(@ytesLong long chunkSizeBytes)1466 public Builder setMinimumNetworkChunkBytes(@BytesLong long chunkSizeBytes) { 1467 if (chunkSizeBytes != NETWORK_BYTES_UNKNOWN && chunkSizeBytes <= 0) { 1468 throw new IllegalArgumentException("Minimum chunk size must be positive"); 1469 } 1470 mMinimumNetworkChunkBytes = chunkSizeBytes; 1471 return this; 1472 } 1473 1474 /** 1475 * Specify that to run this job, the device must be charging (or be a 1476 * non-battery-powered device connected to permanent power, such as Android TV 1477 * devices). This defaults to {@code false}. 1478 * 1479 * <p class="note">For purposes of running jobs, a battery-powered device 1480 * "charging" is not quite the same as simply being connected to power. If the 1481 * device is so busy that the battery is draining despite a power connection, jobs 1482 * with this constraint will <em>not</em> run. This can happen during some 1483 * common use cases such as video chat, particularly if the device is plugged in 1484 * to USB rather than to wall power. 1485 * 1486 * @param requiresCharging Pass {@code true} to require that the device be 1487 * charging in order to run the job. 1488 * @see JobInfo#isRequireCharging() 1489 */ setRequiresCharging(boolean requiresCharging)1490 public Builder setRequiresCharging(boolean requiresCharging) { 1491 mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_CHARGING) 1492 | (requiresCharging ? CONSTRAINT_FLAG_CHARGING : 0); 1493 return this; 1494 } 1495 1496 /** 1497 * Specify that to run this job, the device's battery level must not be low. 1498 * This defaults to false. If true, the job will only run when the battery level 1499 * is not low, which is generally the point where the user is given a "low battery" 1500 * warning. 1501 * @param batteryNotLow Whether or not the device's battery level must not be low. 1502 * @see JobInfo#isRequireBatteryNotLow() 1503 */ setRequiresBatteryNotLow(boolean batteryNotLow)1504 public Builder setRequiresBatteryNotLow(boolean batteryNotLow) { 1505 mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_BATTERY_NOT_LOW) 1506 | (batteryNotLow ? CONSTRAINT_FLAG_BATTERY_NOT_LOW : 0); 1507 return this; 1508 } 1509 1510 /** 1511 * When set {@code true}, ensure that this job will not run if the device is in active use. 1512 * The default state is {@code false}: that is, the for the job to be runnable even when 1513 * someone is interacting with the device. 1514 * 1515 * <p>This state is a loose definition provided by the system. In general, it means that 1516 * the device is not currently being used interactively, and has not been in use for some 1517 * time. As such, it is a good time to perform resource heavy jobs. Bear in mind that 1518 * battery usage will still be attributed to your application, and surfaced to the user in 1519 * battery stats.</p> 1520 * 1521 * <p class="note">Despite the similar naming, this job constraint is <em>not</em> 1522 * related to the system's "device idle" or "doze" states. This constraint only 1523 * determines whether a job is allowed to run while the device is directly in use. 1524 * 1525 * @param requiresDeviceIdle Pass {@code true} to prevent the job from running 1526 * while the device is being used interactively. 1527 * @see JobInfo#isRequireDeviceIdle() 1528 */ setRequiresDeviceIdle(boolean requiresDeviceIdle)1529 public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) { 1530 mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_DEVICE_IDLE) 1531 | (requiresDeviceIdle ? CONSTRAINT_FLAG_DEVICE_IDLE : 0); 1532 return this; 1533 } 1534 1535 /** 1536 * Specify that to run this job, the device's available storage must not be low. 1537 * This defaults to false. If true, the job will only run when the device is not 1538 * in a low storage state, which is generally the point where the user is given a 1539 * "low storage" warning. 1540 * @param storageNotLow Whether or not the device's available storage must not be low. 1541 * @see JobInfo#isRequireStorageNotLow() 1542 */ setRequiresStorageNotLow(boolean storageNotLow)1543 public Builder setRequiresStorageNotLow(boolean storageNotLow) { 1544 mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_STORAGE_NOT_LOW) 1545 | (storageNotLow ? CONSTRAINT_FLAG_STORAGE_NOT_LOW : 0); 1546 return this; 1547 } 1548 1549 /** 1550 * Add a new content: URI that will be monitored with a 1551 * {@link android.database.ContentObserver}, and will cause the job to execute if changed. 1552 * If you have any trigger content URIs associated with a job, it will not execute until 1553 * there has been a change report for one or more of them. 1554 * 1555 * <p>Note that trigger URIs can not be used in combination with 1556 * {@link #setPeriodic(long)} or {@link #setPersisted(boolean)}. To continually monitor 1557 * for content changes, you need to schedule a new JobInfo using the same job ID and 1558 * observing the same URIs in place of calling 1559 * {@link JobService#jobFinished(JobParameters, boolean)}. Remember that 1560 * {@link JobScheduler#schedule(JobInfo)} stops a running job if it uses the same job ID, 1561 * so only call it after you've finished processing the most recent changes (in other words, 1562 * call {@link JobScheduler#schedule(JobInfo)} where you would have normally called 1563 * {@link JobService#jobFinished(JobParameters, boolean)}. 1564 * Following this pattern will ensure you do not lose any content changes: while your 1565 * job is running, the system will continue monitoring for content changes, and propagate 1566 * any changes it sees over to the next job you schedule, so you do not have to worry 1567 * about missing new changes. <b>Scheduling the new job 1568 * before or during processing will cause the current job to be stopped (as described in 1569 * {@link JobScheduler#schedule(JobInfo)}), meaning the wakelock will be released for the 1570 * current job and your app process may be killed since it will no longer be in a valid 1571 * component lifecycle.</b> 1572 * Since {@link JobScheduler#schedule(JobInfo)} stops the current job, you do not 1573 * need to call {@link JobService#jobFinished(JobParameters, boolean)} if you call 1574 * {@link JobScheduler#schedule(JobInfo)} using the same job ID as the 1575 * currently running job.</p> 1576 * 1577 * <p>Because setting this property is not compatible with periodic or 1578 * persisted jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when 1579 * {@link android.app.job.JobInfo.Builder#build()} is called.</p> 1580 * 1581 * <p>The following example shows how this feature can be used to monitor for changes 1582 * in the photos on a device.</p> 1583 * 1584 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/PhotosContentJob.java 1585 * job} 1586 * 1587 * @param uri The content: URI to monitor. 1588 * @see JobInfo#getTriggerContentUris() 1589 */ addTriggerContentUri(@onNull TriggerContentUri uri)1590 public Builder addTriggerContentUri(@NonNull TriggerContentUri uri) { 1591 if (mTriggerContentUris == null) { 1592 mTriggerContentUris = new ArrayList<>(); 1593 } 1594 mTriggerContentUris.add(uri); 1595 return this; 1596 } 1597 1598 /** 1599 * Set the delay (in milliseconds) from when a content change is detected until 1600 * the job is scheduled. If there are more changes during that time, the delay 1601 * will be reset to start at the time of the most recent change. 1602 * @param durationMs Delay after most recent content change, in milliseconds. 1603 * @see JobInfo#getTriggerContentUpdateDelay() 1604 */ setTriggerContentUpdateDelay(long durationMs)1605 public Builder setTriggerContentUpdateDelay(long durationMs) { 1606 mTriggerContentUpdateDelay = durationMs; 1607 return this; 1608 } 1609 1610 /** 1611 * Set the maximum total delay (in milliseconds) that is allowed from the first 1612 * time a content change is detected until the job is scheduled. 1613 * @param durationMs Delay after initial content change, in milliseconds. 1614 * @see JobInfo#getTriggerContentMaxDelay() 1615 */ setTriggerContentMaxDelay(long durationMs)1616 public Builder setTriggerContentMaxDelay(long durationMs) { 1617 mTriggerContentMaxDelay = durationMs; 1618 return this; 1619 } 1620 1621 /** 1622 * Specify that this job should recur with the provided interval, not more than once per 1623 * period. You have no control over when within this interval this job will be executed, 1624 * only the guarantee that it will be executed at most once within this interval, as long 1625 * as the constraints are satisfied. If the constraints are not satisfied within this 1626 * interval, the job will wait until the constraints are satisfied. 1627 * Setting this function on the builder with {@link #setMinimumLatency(long)} or 1628 * {@link #setOverrideDeadline(long)} will result in an error. 1629 * @param intervalMillis Millisecond interval for which this job will repeat. 1630 * @see JobInfo#getIntervalMillis() 1631 * @see JobInfo#getFlexMillis() 1632 */ setPeriodic(long intervalMillis)1633 public Builder setPeriodic(long intervalMillis) { 1634 return setPeriodic(intervalMillis, intervalMillis); 1635 } 1636 1637 /** 1638 * Specify that this job should recur with the provided interval and flex. The job can 1639 * execute at any time in a window of flex length at the end of the period. 1640 * @param intervalMillis Millisecond interval for which this job will repeat. A minimum 1641 * value of {@link #getMinPeriodMillis()} is enforced. 1642 * @param flexMillis Millisecond flex for this job. Flex is clamped to be at least 1643 * {@link #getMinFlexMillis()} or 5 percent of the period, whichever is 1644 * higher. 1645 * @see JobInfo#getIntervalMillis() 1646 * @see JobInfo#getFlexMillis() 1647 */ setPeriodic(long intervalMillis, long flexMillis)1648 public Builder setPeriodic(long intervalMillis, long flexMillis) { 1649 final long minPeriod = getMinPeriodMillis(); 1650 if (intervalMillis < minPeriod) { 1651 Log.w(TAG, "Requested interval " + formatDuration(intervalMillis) + " for job " 1652 + mJobId + " is too small; raising to " + formatDuration(minPeriod)); 1653 intervalMillis = minPeriod; 1654 } 1655 1656 final long percentClamp = 5 * intervalMillis / 100; 1657 final long minFlex = Math.max(percentClamp, getMinFlexMillis()); 1658 if (flexMillis < minFlex) { 1659 Log.w(TAG, "Requested flex " + formatDuration(flexMillis) + " for job " + mJobId 1660 + " is too small; raising to " + formatDuration(minFlex)); 1661 flexMillis = minFlex; 1662 } 1663 1664 mIsPeriodic = true; 1665 mIntervalMillis = intervalMillis; 1666 mFlexMillis = flexMillis; 1667 mHasEarlyConstraint = mHasLateConstraint = true; 1668 return this; 1669 } 1670 1671 /** 1672 * Specify that this job should be delayed by the provided amount of time. The job may not 1673 * run the instant the delay has elapsed. JobScheduler will start the job at an 1674 * indeterminate time after the delay has elapsed. 1675 * <p> 1676 * Because it doesn't make sense setting this property on a periodic job, doing so will 1677 * throw an {@link java.lang.IllegalArgumentException} when 1678 * {@link android.app.job.JobInfo.Builder#build()} is called. 1679 * @param minLatencyMillis Milliseconds before which this job will not be considered for 1680 * execution. 1681 * @see JobInfo#getMinLatencyMillis() 1682 */ setMinimumLatency(long minLatencyMillis)1683 public Builder setMinimumLatency(long minLatencyMillis) { 1684 mMinLatencyMillis = minLatencyMillis; 1685 mHasEarlyConstraint = true; 1686 return this; 1687 } 1688 1689 /** 1690 * Set deadline which is the maximum scheduling latency. The job will be run by this 1691 * deadline even if other requirements (including a delay set through 1692 * {@link #setMinimumLatency(long)}) are not met. 1693 * <p> 1694 * Because it doesn't make sense setting this property on a periodic job, doing so will 1695 * throw an {@link java.lang.IllegalArgumentException} when 1696 * {@link android.app.job.JobInfo.Builder#build()} is called. 1697 * @see JobInfo#getMaxExecutionDelayMillis() 1698 */ setOverrideDeadline(long maxExecutionDelayMillis)1699 public Builder setOverrideDeadline(long maxExecutionDelayMillis) { 1700 mMaxExecutionDelayMillis = maxExecutionDelayMillis; 1701 mHasLateConstraint = true; 1702 return this; 1703 } 1704 1705 /** 1706 * Set up the back-off/retry policy. 1707 * This defaults to some respectable values: {30 seconds, Exponential}. We cap back-off at 1708 * 5hrs. 1709 * <p> 1710 * Note that trying to set a backoff criteria for a job with 1711 * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build(). 1712 * This is because back-off typically does not make sense for these types of jobs. See 1713 * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)} 1714 * for more description of the return value for the case of a job executing while in idle 1715 * mode. 1716 * @param initialBackoffMillis Millisecond time interval to wait initially when job has 1717 * failed. 1718 * @see JobInfo#getInitialBackoffMillis() 1719 * @see JobInfo#getBackoffPolicy() 1720 */ setBackoffCriteria(long initialBackoffMillis, @BackoffPolicy int backoffPolicy)1721 public Builder setBackoffCriteria(long initialBackoffMillis, 1722 @BackoffPolicy int backoffPolicy) { 1723 final long minBackoff = getMinBackoffMillis(); 1724 if (initialBackoffMillis < minBackoff) { 1725 Log.w(TAG, "Requested backoff " + formatDuration(initialBackoffMillis) + " for job " 1726 + mJobId + " is too small; raising to " + formatDuration(minBackoff)); 1727 initialBackoffMillis = minBackoff; 1728 } 1729 1730 mBackoffPolicySet = true; 1731 mInitialBackoffMillis = initialBackoffMillis; 1732 mBackoffPolicy = backoffPolicy; 1733 return this; 1734 } 1735 1736 /** 1737 * Setting this to true indicates that this job is important and needs to run as soon as 1738 * possible with stronger guarantees than regular jobs. These "expedited" jobs will: 1739 * <ol> 1740 * <li>Run as soon as possible</li> 1741 * <li>Be less restricted during Doze and battery saver</li> 1742 * <li>Bypass Doze, app standby, and battery saver network restrictions</li> 1743 * <li>Be less likely to be killed than regular jobs</li> 1744 * <li>Be subject to background location throttling</li> 1745 * </ol> 1746 * 1747 * <p> 1748 * Since these jobs have stronger guarantees than regular jobs, they will be subject to 1749 * stricter quotas. As long as an app has available expedited quota, jobs scheduled with 1750 * this set to true will run with these guarantees. If an app has run out of available 1751 * expedited quota, any pending expedited jobs will run as regular jobs. 1752 * {@link JobParameters#isExpeditedJob()} can be used to know whether the executing job 1753 * has expedited guarantees or not. In addition, {@link JobScheduler#schedule(JobInfo)} 1754 * will immediately return {@link JobScheduler#RESULT_FAILURE} if the app does not have 1755 * available quota (and the job will not be successfully scheduled). 1756 * 1757 * <p> 1758 * Expedited job quota will replenish over time and as the user interacts with the app, 1759 * so you should not have to worry about running out of quota because of processing from 1760 * frequent user engagement. 1761 * 1762 * <p> 1763 * Expedited jobs may only set network, storage-not-low, and persistence constraints. 1764 * No other constraints are allowed. 1765 * 1766 * <p> 1767 * Assuming all constraints remain satisfied (including ideal system load conditions), 1768 * expedited jobs can have an execution time of at least 1 minute. If your 1769 * app has remaining expedited job quota, then the expedited job <i>may</i> potentially run 1770 * longer until remaining quota is used up. Just like with regular jobs, quota is not 1771 * consumed while the app is on top and visible to the user. 1772 * 1773 * <p class="note"> 1774 * Note: Even though expedited jobs are meant to run as soon as possible, they may be 1775 * deferred if the system is under heavy load or requested constraints are not satisfied. 1776 * This delay may be true for expedited jobs of the foreground app on Android version 1777 * {@link Build.VERSION_CODES#S}, but starting from Android version 1778 * {@link Build.VERSION_CODES#TIRAMISU}, expedited jobs for the foreground app are 1779 * guaranteed to be started before {@link JobScheduler#schedule(JobInfo)} returns (assuming 1780 * all requested constraints are satisfied), similar to foreground services. 1781 * 1782 * @see JobInfo#isExpedited() 1783 */ 1784 @NonNull setExpedited(boolean expedited)1785 public Builder setExpedited(boolean expedited) { 1786 if (expedited) { 1787 mFlags |= FLAG_EXPEDITED; 1788 if (mPriority == PRIORITY_DEFAULT) { 1789 // The default priority for EJs is MAX, but only change this if .setPriority() 1790 // hasn't been called yet. 1791 mPriority = PRIORITY_MAX; 1792 } 1793 } else { 1794 if (mPriority == PRIORITY_MAX && (mFlags & FLAG_EXPEDITED) != 0) { 1795 // Reset the priority for the job, but only change this if .setPriority() 1796 // hasn't been called yet. 1797 mPriority = PRIORITY_DEFAULT; 1798 } 1799 mFlags &= (~FLAG_EXPEDITED); 1800 } 1801 return this; 1802 } 1803 1804 /** 1805 * Setting this to true indicates that this job is important while the scheduling app 1806 * is in the foreground or on the temporary whitelist for background restrictions. 1807 * This means that the system will relax doze restrictions on this job during this time. 1808 * 1809 * Apps should use this flag only for short jobs that are essential for the app to function 1810 * properly in the foreground. 1811 * 1812 * Note that once the scheduling app is no longer whitelisted from background restrictions 1813 * and in the background, or the job failed due to unsatisfied constraints, 1814 * this job should be expected to behave like other jobs without this flag. 1815 * 1816 * <p> 1817 * Jobs marked as important-while-foreground are given {@link #PRIORITY_HIGH} by default. 1818 * 1819 * @param importantWhileForeground whether to relax doze restrictions for this job when the 1820 * app is in the foreground. False by default. 1821 * @see JobInfo#isImportantWhileForeground() 1822 * @deprecated Use {@link #setExpedited(boolean)} instead. 1823 */ 1824 @Deprecated setImportantWhileForeground(boolean importantWhileForeground)1825 public Builder setImportantWhileForeground(boolean importantWhileForeground) { 1826 if (importantWhileForeground) { 1827 mFlags |= FLAG_IMPORTANT_WHILE_FOREGROUND; 1828 if (mPriority == PRIORITY_DEFAULT) { 1829 // The default priority for important-while-foreground is HIGH, but only change 1830 // this if .setPriority() hasn't been called yet. 1831 mPriority = PRIORITY_HIGH; 1832 } 1833 } else { 1834 if (mPriority == PRIORITY_HIGH 1835 && (mFlags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0) { 1836 // Reset the priority for the job, but only change this if .setPriority() 1837 // hasn't been called yet. 1838 mPriority = PRIORITY_DEFAULT; 1839 } 1840 mFlags &= (~FLAG_IMPORTANT_WHILE_FOREGROUND); 1841 } 1842 return this; 1843 } 1844 1845 /** 1846 * Setting this to true indicates that this job is designed to prefetch 1847 * content that will make a material improvement to the experience of 1848 * the specific user of this device. For example, fetching top headlines 1849 * of interest to the current user. 1850 * <p> 1851 * Apps targeting Android version {@link Build.VERSION_CODES#TIRAMISU} or later are 1852 * not allowed to have deadlines (set via {@link #setOverrideDeadline(long)} on their 1853 * prefetch jobs. 1854 * <p> 1855 * The system may use this signal to relax the network constraints you 1856 * originally requested, such as allowing a 1857 * {@link JobInfo#NETWORK_TYPE_UNMETERED} job to run over a metered 1858 * network when there is a surplus of metered data available. The system 1859 * may also use this signal in combination with end user usage patterns 1860 * to ensure data is prefetched before the user launches your app. 1861 * @see JobInfo#isPrefetch() 1862 */ setPrefetch(boolean prefetch)1863 public Builder setPrefetch(boolean prefetch) { 1864 if (prefetch) { 1865 mFlags |= FLAG_PREFETCH; 1866 } else { 1867 mFlags &= (~FLAG_PREFETCH); 1868 } 1869 return this; 1870 } 1871 1872 /** 1873 * Set whether or not to persist this job across device reboots. 1874 * 1875 * @param isPersisted True to indicate that the job will be written to 1876 * disk and loaded at boot. 1877 * @see JobInfo#isPersisted() 1878 */ 1879 @RequiresPermission(android.Manifest.permission.RECEIVE_BOOT_COMPLETED) setPersisted(boolean isPersisted)1880 public Builder setPersisted(boolean isPersisted) { 1881 mIsPersisted = isPersisted; 1882 return this; 1883 } 1884 1885 /** 1886 * @return The job object to hand to the JobScheduler. This object is immutable. 1887 */ build()1888 public JobInfo build() { 1889 return build(Compatibility.isChangeEnabled(DISALLOW_DEADLINES_FOR_PREFETCH_JOBS)); 1890 } 1891 1892 /** @hide */ build(boolean disallowPrefetchDeadlines)1893 public JobInfo build(boolean disallowPrefetchDeadlines) { 1894 // This check doesn't need to be inside enforceValidity. It's an unnecessary legacy 1895 // check that would ideally be phased out instead. 1896 if (mBackoffPolicySet && (mConstraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0) { 1897 throw new IllegalArgumentException("An idle mode job will not respect any" + 1898 " back-off policy, so calling setBackoffCriteria with" + 1899 " setRequiresDeviceIdle is an error."); 1900 } 1901 JobInfo jobInfo = new JobInfo(this); 1902 jobInfo.enforceValidity(disallowPrefetchDeadlines); 1903 return jobInfo; 1904 } 1905 1906 /** 1907 * @hide 1908 */ summarize()1909 public String summarize() { 1910 final String service = (mJobService != null) 1911 ? mJobService.flattenToShortString() 1912 : "null"; 1913 return "JobInfo.Builder{job:" + mJobId + "/" + service + "}"; 1914 } 1915 } 1916 1917 /** 1918 * @hide 1919 */ enforceValidity(boolean disallowPrefetchDeadlines)1920 public final void enforceValidity(boolean disallowPrefetchDeadlines) { 1921 // Check that network estimates require network type and are reasonable values. 1922 if ((networkDownloadBytes > 0 || networkUploadBytes > 0 || minimumNetworkChunkBytes > 0) 1923 && networkRequest == null) { 1924 throw new IllegalArgumentException( 1925 "Can't provide estimated network usage without requiring a network"); 1926 } 1927 final long estimatedTransfer; 1928 if (networkUploadBytes == NETWORK_BYTES_UNKNOWN) { 1929 estimatedTransfer = networkDownloadBytes; 1930 } else { 1931 estimatedTransfer = networkUploadBytes 1932 + (networkDownloadBytes == NETWORK_BYTES_UNKNOWN ? 0 : networkDownloadBytes); 1933 } 1934 if (minimumNetworkChunkBytes != NETWORK_BYTES_UNKNOWN 1935 && estimatedTransfer != NETWORK_BYTES_UNKNOWN 1936 && minimumNetworkChunkBytes > estimatedTransfer) { 1937 throw new IllegalArgumentException( 1938 "Minimum chunk size can't be greater than estimated network usage"); 1939 } 1940 if (minimumNetworkChunkBytes != NETWORK_BYTES_UNKNOWN && minimumNetworkChunkBytes <= 0) { 1941 throw new IllegalArgumentException("Minimum chunk size must be positive"); 1942 } 1943 1944 final boolean hasDeadline = maxExecutionDelayMillis != 0L; 1945 // Check that a deadline was not set on a periodic job. 1946 if (isPeriodic) { 1947 if (hasDeadline) { 1948 throw new IllegalArgumentException( 1949 "Can't call setOverrideDeadline() on a periodic job."); 1950 } 1951 if (minLatencyMillis != 0L) { 1952 throw new IllegalArgumentException( 1953 "Can't call setMinimumLatency() on a periodic job"); 1954 } 1955 if (triggerContentUris != null) { 1956 throw new IllegalArgumentException( 1957 "Can't call addTriggerContentUri() on a periodic job"); 1958 } 1959 } 1960 1961 // Prefetch jobs should not have deadlines 1962 if (disallowPrefetchDeadlines && hasDeadline && (flags & FLAG_PREFETCH) != 0) { 1963 throw new IllegalArgumentException( 1964 "Can't call setOverrideDeadline() on a prefetch job."); 1965 } 1966 1967 if (isPersisted) { 1968 // We can't serialize network specifiers 1969 if (networkRequest != null 1970 && networkRequest.getNetworkSpecifier() != null) { 1971 throw new IllegalArgumentException( 1972 "Network specifiers aren't supported for persistent jobs"); 1973 } 1974 if (triggerContentUris != null) { 1975 throw new IllegalArgumentException( 1976 "Can't call addTriggerContentUri() on a persisted job"); 1977 } 1978 if (!transientExtras.isEmpty()) { 1979 throw new IllegalArgumentException( 1980 "Can't call setTransientExtras() on a persisted job"); 1981 } 1982 if (clipData != null) { 1983 throw new IllegalArgumentException( 1984 "Can't call setClipData() on a persisted job"); 1985 } 1986 } 1987 1988 if ((flags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0) { 1989 if (hasEarlyConstraint) { 1990 throw new IllegalArgumentException( 1991 "An important while foreground job cannot have a time delay"); 1992 } 1993 if (mPriority != PRIORITY_HIGH && mPriority != PRIORITY_DEFAULT) { 1994 throw new IllegalArgumentException( 1995 "An important while foreground job must be high or default priority." 1996 + " Don't mark unimportant tasks as important while foreground."); 1997 } 1998 } 1999 2000 final boolean isExpedited = (flags & FLAG_EXPEDITED) != 0; 2001 switch (mPriority) { 2002 case PRIORITY_MAX: 2003 if (!isExpedited) { 2004 throw new IllegalArgumentException("Only expedited jobs can have max priority"); 2005 } 2006 break; 2007 case PRIORITY_HIGH: 2008 if ((flags & FLAG_PREFETCH) != 0) { 2009 throw new IllegalArgumentException("Prefetch jobs cannot be high priority"); 2010 } 2011 if (isPeriodic) { 2012 throw new IllegalArgumentException("Periodic jobs cannot be high priority"); 2013 } 2014 break; 2015 case PRIORITY_DEFAULT: 2016 case PRIORITY_LOW: 2017 case PRIORITY_MIN: 2018 break; 2019 default: 2020 throw new IllegalArgumentException("Invalid priority level provided: " + mPriority); 2021 } 2022 2023 if (isExpedited) { 2024 if (hasEarlyConstraint) { 2025 throw new IllegalArgumentException("An expedited job cannot have a time delay"); 2026 } 2027 if (hasLateConstraint) { 2028 throw new IllegalArgumentException("An expedited job cannot have a deadline"); 2029 } 2030 if (isPeriodic) { 2031 throw new IllegalArgumentException("An expedited job cannot be periodic"); 2032 } 2033 if (mPriority != PRIORITY_MAX && mPriority != PRIORITY_HIGH) { 2034 throw new IllegalArgumentException( 2035 "An expedited job must be high or max priority. Don't use expedited jobs" 2036 + " for unimportant tasks."); 2037 } 2038 if ((constraintFlags & ~CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0 2039 || (flags & ~(FLAG_EXPEDITED | FLAG_EXEMPT_FROM_APP_STANDBY)) != 0) { 2040 throw new IllegalArgumentException( 2041 "An expedited job can only have network and storage-not-low constraints"); 2042 } 2043 if (triggerContentUris != null && triggerContentUris.length > 0) { 2044 throw new IllegalArgumentException( 2045 "Can't call addTriggerContentUri() on an expedited job"); 2046 } 2047 } 2048 } 2049 2050 /** 2051 * Convert a bias integer into a human readable string for debugging. 2052 * @hide 2053 */ getBiasString(int bias)2054 public static String getBiasString(int bias) { 2055 switch (bias) { 2056 case BIAS_DEFAULT: 2057 return BIAS_DEFAULT + " [DEFAULT]"; 2058 case BIAS_SYNC_EXPEDITED: 2059 return BIAS_SYNC_EXPEDITED + " [SYNC_EXPEDITED]"; 2060 case BIAS_SYNC_INITIALIZATION: 2061 return BIAS_SYNC_INITIALIZATION + " [SYNC_INITIALIZATION]"; 2062 case BIAS_BOUND_FOREGROUND_SERVICE: 2063 return BIAS_BOUND_FOREGROUND_SERVICE + " [BFGS_APP]"; 2064 case BIAS_FOREGROUND_SERVICE: 2065 return BIAS_FOREGROUND_SERVICE + " [FGS_APP]"; 2066 case BIAS_TOP_APP: 2067 return BIAS_TOP_APP + " [TOP_APP]"; 2068 2069 // BIAS_ADJ_* are adjustments and not used as real priorities. 2070 // No need to convert to strings. 2071 } 2072 return bias + " [UNKNOWN]"; 2073 } 2074 2075 /** 2076 * Convert a priority integer into a human readable string for debugging. 2077 * @hide 2078 */ getPriorityString(@riority int priority)2079 public static String getPriorityString(@Priority int priority) { 2080 switch (priority) { 2081 case PRIORITY_MIN: 2082 return priority + " [MIN]"; 2083 case PRIORITY_LOW: 2084 return priority + " [LOW]"; 2085 case PRIORITY_DEFAULT: 2086 return priority + " [DEFAULT]"; 2087 case PRIORITY_HIGH: 2088 return priority + " [HIGH]"; 2089 case PRIORITY_MAX: 2090 return priority + " [MAX]"; 2091 } 2092 return priority + " [UNKNOWN]"; 2093 } 2094 } 2095