diff options
author | Matthew Williams <mjwilliams@google.com> | 2014-04-11 15:49:16 -0700 |
---|---|---|
committer | Matthew Williams <mjwilliams@google.com> | 2014-04-21 19:57:49 -0700 |
commit | 6e31c5c82bc5c9bddf9c01d254067ea5bebbd96b (patch) | |
tree | 3dd8ddcc5ea5d9f9a42f87067ec30256601b4474 /core/java/android/content/Task.java | |
parent | 03fee27646564cf1b559b7f8a53d35a1db18d0bd (diff) | |
download | frameworks_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.java | 400 |
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); + } + } + +} |