method public int getClipGrantFlags();
method public android.os.PersistableBundle getExtras();
method public int getJobId();
+ method public android.net.Network getNetwork();
method public android.os.Bundle getTransientExtras();
method public java.lang.String[] getTriggeredContentAuthorities();
method public android.net.Uri[] getTriggeredContentUris();
method public android.graphics.Typeface getTypeface();
method public android.text.style.URLSpan[] getUrls();
method public boolean hasSelection();
- method public void invalidate(int, int, int, int);
method public boolean isAllCaps();
method public boolean isCursorVisible();
method public boolean isElegantTextHeight();
method public int getClipGrantFlags();
method public android.os.PersistableBundle getExtras();
method public int getJobId();
+ method public android.net.Network getNetwork();
method public android.os.Bundle getTransientExtras();
method public java.lang.String[] getTriggeredContentAuthorities();
method public android.net.Uri[] getTriggeredContentUris();
method public android.graphics.Typeface getTypeface();
method public android.text.style.URLSpan[] getUrls();
method public boolean hasSelection();
- method public void invalidate(int, int, int, int);
method public boolean isAllCaps();
method public boolean isCursorVisible();
method public boolean isElegantTextHeight();
method public int getClipGrantFlags();
method public android.os.PersistableBundle getExtras();
method public int getJobId();
+ method public android.net.Network getNetwork();
method public android.os.Bundle getTransientExtras();
method public java.lang.String[] getTriggeredContentAuthorities();
method public android.net.Uri[] getTriggeredContentUris();
method public android.graphics.Typeface getTypeface();
method public android.text.style.URLSpan[] getUrls();
method public boolean hasSelection();
- method public void invalidate(int, int, int, int);
method public boolean isAllCaps();
method public boolean isCursorVisible();
method public boolean isElegantTextHeight();
}
/**
- * Set some description of the kind of network type your job needs to have.
- * Not calling this function means the network is not necessary, as the default is
- * {@link #NETWORK_TYPE_NONE}.
- * Bear in mind that calling this function defines network as a strict requirement for your
- * job. If the network requested is not available your job will never run. See
- * {@link #setOverrideDeadline(long)} to change this behaviour.
+ * Set some description of the kind of network type your job needs to
+ * have. Not calling this function means the network is not necessary,
+ * as the default is {@link #NETWORK_TYPE_NONE}. Bear in mind that
+ * calling this function defines network as a strict requirement for
+ * your job. If the network requested is not available your job will
+ * never run. See {@link #setOverrideDeadline(long)} to change this
+ * behaviour.
+ * <p class="note">
+ * Note: When your job executes in
+ * {@link JobService#onStartJob(JobParameters)}, be sure to use the
+ * specific network returned by {@link JobParameters#getNetwork()},
+ * otherwise you'll use the default network which may not meet this
+ * constraint.
+ *
+ * @see JobParameters#getNetwork()
*/
public Builder setRequiredNetworkType(@NetworkType int networkType) {
mNetworkType = networkType;
import android.annotation.Nullable;
import android.app.job.IJobCallback;
import android.content.ClipData;
+import android.net.Network;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
private final boolean overrideDeadlineExpired;
private final Uri[] mTriggeredContentUris;
private final String[] mTriggeredContentAuthorities;
+ private final Network network;
private int stopReason; // Default value of stopReason is REASON_CANCELED
public JobParameters(IBinder callback, int jobId, PersistableBundle extras,
Bundle transientExtras, ClipData clipData, int clipGrantFlags,
boolean overrideDeadlineExpired, Uri[] triggeredContentUris,
- String[] triggeredContentAuthorities) {
+ String[] triggeredContentAuthorities, Network network) {
this.jobId = jobId;
this.extras = extras;
this.transientExtras = transientExtras;
this.overrideDeadlineExpired = overrideDeadlineExpired;
this.mTriggeredContentUris = triggeredContentUris;
this.mTriggeredContentAuthorities = triggeredContentAuthorities;
+ this.network = network;
}
/**
}
/**
+ * Return the network that should be used to perform any network requests
+ * for this job.
+ * <p>
+ * Devices may have multiple active network connections simultaneously, or
+ * they may not have a default network route at all. To correctly handle all
+ * situations like this, your job should always use the network returned by
+ * this method instead of implicitly using the default network route.
+ * <p>
+ * Note that the system may relax the constraints you originally requested,
+ * such as allowing a {@link JobInfo#NETWORK_TYPE_UNMETERED} job to run over
+ * a metered network when there is a surplus of metered data available.
+ *
+ * @return the network that should be used to perform any network requests
+ * for this job, or {@code null} if this job didn't set any required
+ * network type.
+ * @see JobInfo.Builder#setRequiredNetworkType(int)
+ */
+ public @Nullable Network getNetwork() {
+ return network;
+ }
+
+ /**
* Dequeue the next pending {@link JobWorkItem} from these JobParameters associated with their
* currently running job. Calling this method when there is no more work available and all
* previously dequeued work has been completed will result in the system taking care of
overrideDeadlineExpired = in.readInt() == 1;
mTriggeredContentUris = in.createTypedArray(Uri.CREATOR);
mTriggeredContentAuthorities = in.createStringArray();
+ if (in.readInt() != 0) {
+ network = Network.CREATOR.createFromParcel(in);
+ } else {
+ network = null;
+ }
stopReason = in.readInt();
}
dest.writeInt(overrideDeadlineExpired ? 1 : 0);
dest.writeTypedArray(mTriggeredContentUris, flags);
dest.writeStringArray(mTriggeredContentAuthorities);
+ if (network != null) {
+ dest.writeInt(1);
+ network.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
dest.writeInt(stopReason);
}
final JobInfo ji = job.getJob();
mParams = new JobParameters(mRunningCallback, job.getJobId(), ji.getExtras(),
ji.getTransientExtras(), ji.getClipData(), ji.getClipGrantFlags(),
- isDeadlineExpired, triggeredUris, triggeredAuthorities);
+ isDeadlineExpired, triggeredUris, triggeredAuthorities, job.network);
mExecutionStartTimeElapsed = SystemClock.elapsedRealtime();
// Once we'e begun executing a job, we by definition no longer care whether
changed |= jobStatus.setUnmeteredConstraintSatisfied(unmetered);
changed |= jobStatus.setNotRoamingConstraintSatisfied(notRoaming);
+ // Pass along the evaluated network for job to use; prevents race
+ // conditions as default routes change over time, and opens the door to
+ // using non-default routes.
+ jobStatus.network = network;
+
// Track system-uid connected/validated as a general reportable proxy for the
// overall state of connectivity constraint satisfiability.
if (jobUid == Process.SYSTEM_UID) {
import android.app.job.JobWorkItem;
import android.content.ClipData;
import android.content.ComponentName;
+import android.net.Network;
import android.net.Uri;
import android.os.RemoteException;
import android.os.SystemClock;
// These are filled in by controllers when preparing for execution.
public ArraySet<Uri> changedUris;
public ArraySet<String> changedAuthorities;
+ public Network network;
public int lastEvaluatedPriority;
}
}
}
+ if (network != null) {
+ pw.print(prefix); pw.print("Network: "); pw.println(network);
+ }
if (pendingWork != null && pendingWork.size() > 0) {
pw.print(prefix); pw.println("Pending work:");
for (int i = 0; i < pendingWork.size(); i++) {