summaryrefslogtreecommitdiffstats
path: root/core/java/android/content/Task.java
diff options
context:
space:
mode:
authorMatthew Williams <mjwilliams@google.com>2014-04-11 15:49:16 -0700
committerMatthew Williams <mjwilliams@google.com>2014-04-21 19:57:49 -0700
commit6e31c5c82bc5c9bddf9c01d254067ea5bebbd96b (patch)
tree3dd8ddcc5ea5d9f9a42f87067ec30256601b4474 /core/java/android/content/Task.java
parent03fee27646564cf1b559b7f8a53d35a1db18d0bd (diff)
downloadframeworks_base-6e31c5c82bc5c9bddf9c01d254067ea5bebbd96b.zip
frameworks_base-6e31c5c82bc5c9bddf9c01d254067ea5bebbd96b.tar.gz
frameworks_base-6e31c5c82bc5c9bddf9c01d254067ea5bebbd96b.tar.bz2
TaskManager API first pass.
This is a very barebones first pass, meant to ensure we're all on the same page, and also get feedback. Change-Id: I7d5492dc5aafbe583f7c2d97ebf1444b6d2e068a
Diffstat (limited to 'core/java/android/content/Task.java')
-rw-r--r--core/java/android/content/Task.java400
1 files changed, 400 insertions, 0 deletions
diff --git a/core/java/android/content/Task.java b/core/java/android/content/Task.java
new file mode 100644
index 0000000..ed5ed88
--- /dev/null
+++ b/core/java/android/content/Task.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.content;
+
+import android.app.task.TaskService;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container of data passed to the {@link android.content.TaskManager} fully encapsulating the
+ * parameters required to schedule work against the calling application. These are constructed
+ * using the {@link Task.Builder}.
+ */
+public class Task implements Parcelable {
+
+ public interface NetworkType {
+ public final int ANY = 0;
+ public final int UNMETERED = 1;
+ }
+
+ /**
+ * Linear: retry_time(failure_time, t) = failure_time + initial_retry_delay * t, t >= 1
+ * Expon: retry_time(failure_time, t) = failure_time + initial_retry_delay ^ t, t >= 1
+ */
+ public interface BackoffPolicy {
+ public final int LINEAR = 0;
+ public final int EXPONENTIAL = 1;
+ }
+
+ /**
+ * Unique task id associated with this class. This is assigned to your task by the scheduler.
+ */
+ public int getTaskId() {
+ return taskId;
+ }
+
+ /**
+ * Bundle of extras which are returned to your application at execution time.
+ */
+ public Bundle getExtras() {
+ return extras;
+ }
+
+ /**
+ * Name of the service endpoint that will be called back into by the TaskManager.
+ */
+ public String getServiceClassName() {
+ return serviceClassName;
+ }
+
+ /**
+ * Whether this task needs the device to be plugged in.
+ */
+ public boolean isRequireCharging() {
+ return requireCharging;
+ }
+
+ /**
+ * Whether this task needs the device to be in an Idle maintenance window.
+ */
+ public boolean isRequireDeviceIdle() {
+ return requireDeviceIdle;
+ }
+
+ /**
+ * See {@link android.content.Task.NetworkType} for a description of this value.
+ */
+ public int getNetworkCapabilities() {
+ return networkCapabilities;
+ }
+
+ /**
+ * Set for a task that does not recur periodically, to specify a delay after which the task
+ * will be eligible for execution. This value is not set if the task recurs periodically.
+ */
+ public long getMinLatencyMillis() {
+ return minLatencyMillis;
+ }
+
+ /**
+ * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the task recurs
+ * periodically.
+ */
+ public long getMaxExecutionDelayMillis() {
+ return maxExecutionDelayMillis;
+ }
+
+ /**
+ * Track whether this task will repeat with a given period.
+ */
+ public boolean isPeriodic() {
+ return isPeriodic;
+ }
+
+ /**
+ * Set to the interval between occurrences of this task. This value is <b>not</b> set if the
+ * task does not recur periodically.
+ */
+ public long getIntervalMillis() {
+ return intervalMillis;
+ }
+
+ /**
+ * The amount of time the TaskManager will wait before rescheduling a failed task. This value
+ * will be increased depending on the backoff policy specified at task creation time. Defaults
+ * to 5 seconds.
+ */
+ public long getInitialBackoffMillis() {
+ return initialBackoffMillis;
+ }
+
+ /**
+ * See {@link android.content.Task.BackoffPolicy} for an explanation of the values this field
+ * can take. This defaults to exponential.
+ */
+ public int getBackoffPolicy() {
+ return backoffPolicy;
+ }
+
+ private final int taskId;
+ // TODO: Change this to use PersistableBundle when that lands in master.
+ private final Bundle extras;
+ private final String serviceClassName;
+ private final boolean requireCharging;
+ private final boolean requireDeviceIdle;
+ private final int networkCapabilities;
+ private final long minLatencyMillis;
+ private final long maxExecutionDelayMillis;
+ private final boolean isPeriodic;
+ private final long intervalMillis;
+ private final long initialBackoffMillis;
+ private final int backoffPolicy;
+
+ private Task(Parcel in) {
+ taskId = in.readInt();
+ extras = in.readBundle();
+ serviceClassName = in.readString();
+ requireCharging = in.readInt() == 1;
+ requireDeviceIdle = in.readInt() == 1;
+ networkCapabilities = in.readInt();
+ minLatencyMillis = in.readLong();
+ maxExecutionDelayMillis = in.readLong();
+ isPeriodic = in.readInt() == 1;
+ intervalMillis = in.readLong();
+ initialBackoffMillis = in.readLong();
+ backoffPolicy = in.readInt();
+ }
+
+ private Task(Task.Builder b) {
+ taskId = b.mTaskId;
+ extras = new Bundle(b.mExtras);
+ serviceClassName = b.mTaskServiceClassName;
+ requireCharging = b.mRequiresCharging;
+ requireDeviceIdle = b.mRequiresDeviceIdle;
+ networkCapabilities = b.mNetworkCapabilities;
+ minLatencyMillis = b.mMinLatencyMillis;
+ maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
+ isPeriodic = b.mIsPeriodic;
+ intervalMillis = b.mIntervalMillis;
+ initialBackoffMillis = b.mInitialBackoffMillis;
+ backoffPolicy = b.mBackoffPolicy;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(taskId);
+ out.writeBundle(extras);
+ out.writeString(serviceClassName);
+ out.writeInt(requireCharging ? 1 : 0);
+ out.writeInt(requireDeviceIdle ? 1 : 0);
+ out.writeInt(networkCapabilities);
+ out.writeLong(minLatencyMillis);
+ out.writeLong(maxExecutionDelayMillis);
+ out.writeInt(isPeriodic ? 1 : 0);
+ out.writeLong(intervalMillis);
+ out.writeLong(initialBackoffMillis);
+ out.writeInt(backoffPolicy);
+ }
+
+ public static final Creator<Task> CREATOR = new Creator<Task>() {
+ @Override
+ public Task createFromParcel(Parcel in) {
+ return new Task(in);
+ }
+
+ @Override
+ public Task[] newArray(int size) {
+ return new Task[size];
+ }
+ };
+
+ /**
+ * Builder class for constructing {@link Task} objects.
+ */
+ public final class Builder {
+ private int mTaskId;
+ private Bundle mExtras;
+ private String mTaskServiceClassName;
+ // Requirements.
+ private boolean mRequiresCharging;
+ private boolean mRequiresDeviceIdle;
+ private int mNetworkCapabilities;
+ // One-off parameters.
+ private long mMinLatencyMillis;
+ private long mMaxExecutionDelayMillis;
+ // Periodic parameters.
+ private boolean mIsPeriodic;
+ private long mIntervalMillis;
+ // Back-off parameters.
+ private long mInitialBackoffMillis = 5000L;
+ private int mBackoffPolicy = BackoffPolicy.EXPONENTIAL;
+ /** Easy way to track whether the client has tried to set a back-off policy. */
+ private boolean mBackoffPolicySet = false;
+
+ /**
+ * @param taskId Application-provided id for this task. Subsequent calls to cancel, or
+ * tasks created with the same taskId, will update the pre-existing task with
+ * the same id.
+ * @param cls The endpoint that you implement that will receive the callback from the
+ * TaskManager.
+ */
+ public Builder(int taskId, Class<TaskService> cls) {
+ mTaskServiceClassName = cls.getClass().getName();
+ mTaskId = taskId;
+ }
+
+ /**
+ * Set optional extras. This is persisted, so we only allow primitive types.
+ * @param extras Bundle containing extras you want the scheduler to hold on to for you.
+ */
+ public Builder setExtras(Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
+ * Set some description of the kind of network capabilities you would like to have. This
+ * will be a parameter defined in {@link android.content.Task.NetworkType}.
+ * Not calling this function means the network is not necessary.
+ * Bear in mind that calling this function defines network as a strict requirement for your
+ * task if the network requested is not available your task will never run. See
+ * {@link #setOverrideDeadline(long)} to change this behaviour.
+ */
+ public Builder setRequiredNetworkCapabilities(int networkCapabilities) {
+ mNetworkCapabilities = networkCapabilities;
+ return this;
+ }
+
+ /*
+ * Specify that to run this task, the device needs to be plugged in. This defaults to
+ * false.
+ * @param requireCharging Whether or not the device is plugged in.
+ */
+ public Builder setRequiresCharging(boolean requiresCharging) {
+ mRequiresCharging = requiresCharging;
+ return this;
+ }
+
+ /**
+ * Specify that to run, the task needs the device to be in idle mode. This defaults to
+ * false.
+ * <p>Idle mode is a loose definition provided by the system, which means that the device
+ * is not in use, and has not been in use for some time. As such, it is a good time to
+ * perform resource heavy tasks. Bear in mind that battery usage will still be attributed
+ * to your application, and surfaced to the user in battery stats.</p>
+ * @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
+ * window.
+ */
+ public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
+ mRequiresDeviceIdle = requiresDeviceIdle;
+ return this;
+ }
+
+ /**
+ * Specify that this task should recur with the provided interval, not more than once per
+ * period. You have no control over when within this interval this task will be executed,
+ * only the guarantee that it will be executed at most once within this interval.
+ * A periodic task will be repeated until the phone is turned off, however it will only be
+ * persisted if the client app has declared the
+ * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission. You can schedule
+ * periodic tasks without this permission, they simply will cease to exist after the phone
+ * restarts.
+ * Setting this function on the builder with {@link #setMinimumLatency(long)} or
+ * {@link #setOverrideDeadline(long)} will result in an error.
+ * @param intervalMillis Millisecond interval for which this task will repeat.
+ */
+ public Builder setPeriodic(long intervalMillis) {
+ mIsPeriodic = true;
+ mIntervalMillis = intervalMillis;
+ return this;
+ }
+
+ /**
+ * Specify that this task should be delayed by the provided amount of time.
+ * Because it doesn't make sense setting this property on a periodic task, doing so will
+ * throw an {@link java.lang.IllegalArgumentException} when
+ * {@link android.content.Task.Builder#build()} is called.
+ * @param minLatencyMillis Milliseconds before which this task will not be considered for
+ * execution.
+ */
+ public Builder setMinimumLatency(long minLatencyMillis) {
+ mMinLatencyMillis = minLatencyMillis;
+ return this;
+ }
+
+ /**
+ * Set deadline which is the maximum scheduling latency. The task will be run by this
+ * deadline even if other requirements are not met. Because it doesn't make sense setting
+ * this property on a periodic task, doing so will throw an
+ * {@link java.lang.IllegalArgumentException} when
+ * {@link android.content.Task.Builder#build()} is called.
+ */
+ public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
+ mMaxExecutionDelayMillis = maxExecutionDelayMillis;
+ return this;
+ }
+
+ /**
+ * Set up the back-off/retry policy.
+ * This defaults to some respectable values: {5 seconds, Exponential}. We cap back-off at
+ * 1hr.
+ * Note that trying to set a backoff criteria for a task with
+ * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
+ * This is because back-off typically does not make sense for these types of tasks. See
+ * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
+ * for more description of the return value for the case of a task executing while in idle
+ * mode.
+ * @param initialBackoffMillis Millisecond time interval to wait initially when task has
+ * failed.
+ * @param backoffPolicy is one of {@link BackoffPolicy}
+ */
+ public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) {
+ mBackoffPolicySet = true;
+ mInitialBackoffMillis = initialBackoffMillis;
+ mBackoffPolicy = backoffPolicy;
+ return this;
+ }
+
+ /**
+ * @return The task object to hand to the TaskManager. This object is immutable.
+ */
+ public Task build() {
+ // Check that extras bundle only contains primitive types.
+ try {
+ for (String key : extras.keySet()) {
+ Object value = extras.get(key);
+ if (value == null) continue;
+ if (value instanceof Long) continue;
+ if (value instanceof Integer) continue;
+ if (value instanceof Boolean) continue;
+ if (value instanceof Float) continue;
+ if (value instanceof Double) continue;
+ if (value instanceof String) continue;
+ throw new IllegalArgumentException("Unexpected value type: "
+ + value.getClass().getName());
+ }
+ } catch (IllegalArgumentException e) {
+ throw e;
+ } catch (RuntimeException exc) {
+ throw new IllegalArgumentException("error unparcelling Bundle", exc);
+ }
+ // Check that a deadline was not set on a periodic task.
+ if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
+ throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
+ "periodic task.");
+ }
+ if (mIsPeriodic && (mMinLatencyMillis != 0L)) {
+ throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
+ "periodic task");
+ }
+ if (mBackoffPolicySet && mRequiresDeviceIdle) {
+ throw new IllegalArgumentException("An idle mode task will not respect any" +
+ " back-off policy, so calling setBackoffCriteria with" +
+ " setRequiresDeviceIdle is an error.");
+ }
+ return new Task(this);
+ }
+ }
+
+}