Merge "TaskManager API first pass."
This commit is contained in:
committed by
Android (Google) Code Review
commit
674bc2fca5
@@ -76,6 +76,8 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/app/ISearchManagerCallback.aidl \
|
||||
core/java/android/app/IServiceConnection.aidl \
|
||||
core/java/android/app/IStopUserCallback.aidl \
|
||||
core/java/android/app/task/ITaskCallback.aidl \
|
||||
core/java/android/app/task/ITaskService.aidl \
|
||||
core/java/android/app/IThumbnailReceiver.aidl \
|
||||
core/java/android/app/IThumbnailRetriever.aidl \
|
||||
core/java/android/app/ITransientNotification.aidl \
|
||||
|
||||
@@ -5166,6 +5166,26 @@ package android.app.maintenance {
|
||||
|
||||
}
|
||||
|
||||
package android.app.task {
|
||||
|
||||
public class TaskParams implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public int getTaskId();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
}
|
||||
|
||||
public abstract class TaskService extends android.app.Service {
|
||||
ctor public TaskService();
|
||||
method public final android.os.IBinder onBind(android.content.Intent);
|
||||
method public abstract void onStartTask(android.app.task.TaskParams, android.os.Bundle);
|
||||
method public abstract boolean onStopTask(android.app.task.TaskParams);
|
||||
method public final void taskFinished(android.app.task.TaskParams, boolean);
|
||||
field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_TASK_SERVICE";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.appwidget {
|
||||
|
||||
public class AppWidgetHost {
|
||||
@@ -7528,6 +7548,55 @@ package android.content {
|
||||
method public abstract void onStatusChanged(int);
|
||||
}
|
||||
|
||||
public class Task implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public int getBackoffPolicy();
|
||||
method public android.os.Bundle getExtras();
|
||||
method public long getInitialBackoffMillis();
|
||||
method public long getIntervalMillis();
|
||||
method public long getMaxExecutionDelayMillis();
|
||||
method public long getMinLatencyMillis();
|
||||
method public int getNetworkCapabilities();
|
||||
method public java.lang.String getServiceClassName();
|
||||
method public int getTaskId();
|
||||
method public boolean isPeriodic();
|
||||
method public boolean isRequireCharging();
|
||||
method public boolean isRequireDeviceIdle();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
}
|
||||
|
||||
public static abstract interface Task.BackoffPolicy {
|
||||
field public static final int EXPONENTIAL = 1; // 0x1
|
||||
field public static final int LINEAR = 0; // 0x0
|
||||
}
|
||||
|
||||
public final class Task.Builder {
|
||||
ctor public Task.Builder(int, java.lang.Class<android.app.task.TaskService>);
|
||||
method public android.content.Task build();
|
||||
method public android.content.Task.Builder setBackoffCriteria(long, int);
|
||||
method public android.content.Task.Builder setExtras(android.os.Bundle);
|
||||
method public android.content.Task.Builder setMinimumLatency(long);
|
||||
method public android.content.Task.Builder setOverrideDeadline(long);
|
||||
method public android.content.Task.Builder setPeriodic(long);
|
||||
method public android.content.Task.Builder setRequiredNetworkCapabilities(int);
|
||||
method public android.content.Task.Builder setRequiresCharging(boolean);
|
||||
method public android.content.Task.Builder setRequiresDeviceIdle(boolean);
|
||||
}
|
||||
|
||||
public static abstract interface Task.NetworkType {
|
||||
field public static final int ANY = 0; // 0x0
|
||||
field public static final int UNMETERED = 1; // 0x1
|
||||
}
|
||||
|
||||
public abstract class TaskManager {
|
||||
ctor public TaskManager();
|
||||
method public abstract void cancel(int);
|
||||
method public abstract void cancelAll();
|
||||
method public abstract java.util.List<android.content.Task> getAllPendingTasks();
|
||||
method public abstract int schedule(android.content.Task);
|
||||
}
|
||||
|
||||
public class UriMatcher {
|
||||
ctor public UriMatcher(int);
|
||||
method public void addURI(java.lang.String, java.lang.String, int);
|
||||
|
||||
52
core/java/android/app/task/ITaskCallback.aidl
Normal file
52
core/java/android/app/task/ITaskCallback.aidl
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright 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.app.task;
|
||||
|
||||
import android.app.task.ITaskService;
|
||||
import android.app.task.TaskParams;
|
||||
|
||||
/**
|
||||
* The server side of the TaskManager IPC protocols. The app-side implementation
|
||||
* invokes on this interface to indicate completion of the (asynchronous) instructions
|
||||
* issued by the server.
|
||||
*
|
||||
* In all cases, the 'who' parameter is the caller's service binder, used to track
|
||||
* which Task Service instance is reporting.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
interface ITaskCallback {
|
||||
/**
|
||||
* Immediate callback to the system after sending a start signal, used to quickly detect ANR.
|
||||
*
|
||||
* @param taskId Unique integer used to identify this task.
|
||||
*/
|
||||
void acknowledgeStartMessage(int taskId);
|
||||
/**
|
||||
* Immediate callback to the system after sending a stop signal, used to quickly detect ANR.
|
||||
*
|
||||
* @param taskId Unique integer used to identify this task.
|
||||
*/
|
||||
void acknowledgeStopMessage(int taskId);
|
||||
/*
|
||||
* Tell the task manager that the client is done with its execution, so that it can go on to
|
||||
* the next one and stop attributing wakelock time to us etc.
|
||||
*
|
||||
* @param taskId Unique integer used to identify this task.
|
||||
*/
|
||||
void taskFinished(int taskId, boolean taskFailed);
|
||||
}
|
||||
35
core/java/android/app/task/ITaskService.aidl
Normal file
35
core/java/android/app/task/ITaskService.aidl
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright 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.app.task;
|
||||
|
||||
import android.app.task.ITaskCallback;
|
||||
import android.app.task.TaskParams;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* Interface that the framework uses to communicate with application code
|
||||
* that implements a TaskService. End user code does not implement this interface directly;
|
||||
* instead, the app's idle service implementation will extend android.app.maintenance.IdleService.
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface ITaskService {
|
||||
/** Begin execution of application's task. */
|
||||
void startTask(in TaskParams taskParams);
|
||||
/** Stop execution of application's task. */
|
||||
void stopTask(in TaskParams taskParams);
|
||||
}
|
||||
19
core/java/android/app/task/TaskParams.aidl
Normal file
19
core/java/android/app/task/TaskParams.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright 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.app.task;
|
||||
|
||||
parcelable TaskParams;
|
||||
87
core/java/android/app/task/TaskParams.java
Normal file
87
core/java/android/app/task/TaskParams.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.app.task;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Contains the parameters used to configure/identify your task. You do not create this object
|
||||
* yourself, instead it is handed in to your application by the System.
|
||||
*/
|
||||
public class TaskParams implements Parcelable {
|
||||
|
||||
private final int taskId;
|
||||
private final Bundle extras;
|
||||
private final IBinder mCallback;
|
||||
|
||||
/**
|
||||
* @return The unique id of this task, specified at creation time using
|
||||
* {@link android.content.Task.Builder#Builder(int, Class)}.
|
||||
*/
|
||||
public int getTaskId() {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The extras you passed in when constructing this task with
|
||||
* {@link android.content.Task.Builder#setExtras(android.os.Bundle)}. This will
|
||||
* never be null. If you did not set any extras this will be an empty bundle.
|
||||
*/
|
||||
public Bundle getExtras() {
|
||||
return extras;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public ITaskCallback getCallback() {
|
||||
return ITaskCallback.Stub.asInterface(mCallback);
|
||||
}
|
||||
|
||||
private TaskParams(Parcel in) {
|
||||
taskId = in.readInt();
|
||||
extras = in.readBundle();
|
||||
mCallback = in.readStrongBinder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(taskId);
|
||||
dest.writeBundle(extras);
|
||||
dest.writeStrongBinder(mCallback);
|
||||
}
|
||||
|
||||
public static final Creator<TaskParams> CREATOR = new Creator<TaskParams>() {
|
||||
@Override
|
||||
public TaskParams createFromParcel(Parcel in) {
|
||||
return new TaskParams(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskParams[] newArray(int size) {
|
||||
return new TaskParams[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
260
core/java/android/app/task/TaskService.java
Normal file
260
core/java/android/app/task/TaskService.java
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* 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.app.task;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
/**
|
||||
* <p>Entry point for the callback from the {@link android.content.TaskManager}.</p>
|
||||
* <p>This is the base class that handles asynchronous requests that were previously scheduled. You
|
||||
* are responsible for overriding {@Link AbstracTaskService#onPerformTask(Bundle)}, which is where
|
||||
* you will implement your task logic.</p>
|
||||
* <p>This service executes each incoming task on a {@link android.os.Handler} running on your
|
||||
* application's main thread. This means that you <b>must</b> offload your execution logic to
|
||||
* another thread/handler/{@link android.os.AsyncTask} of your choosing. Not doing so will result
|
||||
* in blocking any future callbacks from the TaskManager - specifically
|
||||
* {@link #onStopTask(android.app.task.TaskParams)}, which is meant to inform you that the
|
||||
* scheduling requirements are no longer being met.</p>
|
||||
*/
|
||||
public abstract class TaskService extends Service {
|
||||
private static final String TAG = "TaskService";
|
||||
|
||||
/**
|
||||
* Task services must be protected with this permission:
|
||||
*
|
||||
* <pre class="prettyprint">
|
||||
* <service android:name="MyTaskService"
|
||||
* android:permission="android.permission.BIND_TASK_SERVICE" >
|
||||
* ...
|
||||
* </service>
|
||||
* </pre>
|
||||
*
|
||||
* <p>If a task service is declared in the manifest but not protected with this
|
||||
* permission, that service will be ignored by the OS.
|
||||
*/
|
||||
public static final String PERMISSION_BIND =
|
||||
"android.permission.BIND_TASK_SERVICE";
|
||||
|
||||
/**
|
||||
* Identifier for a message that will result in a call to
|
||||
* {@link #onStartTask(android.app.task.TaskParams, android.os.Bundle)}.
|
||||
*/
|
||||
private final int MSG_EXECUTE_TASK = 0;
|
||||
/**
|
||||
* Message that will result in a call to {@link #onStopTask(android.app.task.TaskParams)}.
|
||||
*/
|
||||
private final int MSG_STOP_TASK = 1;
|
||||
/**
|
||||
* Message that the client has completed execution of this task.
|
||||
*/
|
||||
private final int MSG_TASK_FINISHED = 2;
|
||||
|
||||
/** Lock object for {@link #mHandler}. */
|
||||
private final Object mHandlerLock = new Object();
|
||||
|
||||
/**
|
||||
* Handler we post tasks to. Responsible for calling into the client logic, and handling the
|
||||
* callback to the system.
|
||||
*/
|
||||
@GuardedBy("mHandlerLock")
|
||||
TaskHandler mHandler;
|
||||
|
||||
/** Binder for this service. */
|
||||
ITaskService mBinder = new ITaskService.Stub() {
|
||||
@Override
|
||||
public void startTask(TaskParams taskParams) {
|
||||
ensureHandler();
|
||||
Message m = Message.obtain(mHandler, MSG_EXECUTE_TASK, taskParams);
|
||||
m.sendToTarget();
|
||||
}
|
||||
@Override
|
||||
public void stopTask(TaskParams taskParams) {
|
||||
ensureHandler();
|
||||
Message m = Message.obtain(mHandler, MSG_STOP_TASK, taskParams);
|
||||
m.sendToTarget();
|
||||
}
|
||||
};
|
||||
|
||||
/** @hide */
|
||||
void ensureHandler() {
|
||||
synchronized (mHandlerLock) {
|
||||
if (mHandler == null) {
|
||||
mHandler = new TaskHandler(getMainLooper());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs on application's main thread - callbacks are meant to offboard work to some other
|
||||
* (app-specified) mechanism.
|
||||
* @hide
|
||||
*/
|
||||
class TaskHandler extends Handler {
|
||||
TaskHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
final TaskParams params = (TaskParams) msg.obj;
|
||||
switch (msg.what) {
|
||||
case MSG_EXECUTE_TASK:
|
||||
try {
|
||||
TaskService.this.onStartTask(params);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error while executing task: " + params.getTaskId());
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
maybeAckMessageReceived(params, MSG_EXECUTE_TASK);
|
||||
}
|
||||
break;
|
||||
case MSG_STOP_TASK:
|
||||
try {
|
||||
TaskService.this.onStopTask(params);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Application unable to handle onStopTask.", e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
maybeAckMessageReceived(params, MSG_STOP_TASK);
|
||||
}
|
||||
break;
|
||||
case MSG_TASK_FINISHED:
|
||||
final boolean needsReschedule = (msg.arg2 == 1);
|
||||
ITaskCallback callback = params.getCallback();
|
||||
if (callback != null) {
|
||||
try {
|
||||
callback.taskFinished(params.getTaskId(), needsReschedule);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error reporting task finish to system: binder has gone" +
|
||||
"away.");
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "finishTask() called for a nonexistent task id.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unrecognised message received.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Messages come in on the application's main thread, so rather than run the risk of
|
||||
* waiting for an app that may be doing something foolhardy, we ack to the system after
|
||||
* processing a message. This allows us to throw up an ANR dialogue as quickly as possible.
|
||||
* @param params id of the task we're acking.
|
||||
* @param state Information about what message we're acking.
|
||||
*/
|
||||
private void maybeAckMessageReceived(TaskParams params, int state) {
|
||||
final ITaskCallback callback = params.getCallback();
|
||||
final int taskId = params.getTaskId();
|
||||
if (callback != null) {
|
||||
try {
|
||||
if (state == MSG_EXECUTE_TASK) {
|
||||
callback.acknowledgeStartMessage(taskId);
|
||||
} else if (state == MSG_STOP_TASK) {
|
||||
callback.acknowledgeStopMessage(taskId);
|
||||
}
|
||||
} catch(RemoteException e) {
|
||||
Log.e(TAG, "System unreachable for starting task.");
|
||||
}
|
||||
} else {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, state + ": Attempting to ack a task that has already been" +
|
||||
"processed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public final IBinder onBind(Intent intent) {
|
||||
return mBinder.asBinder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method with the callback logic for your task. Any such logic needs to be
|
||||
* performed on a separate thread, as this function is executed on your application's main
|
||||
* thread.
|
||||
*
|
||||
* @param params Parameters specifying info about this task, including the extras bundle you
|
||||
* optionally provided at task-creation time.
|
||||
*/
|
||||
public abstract void onStartTask(TaskParams params);
|
||||
|
||||
/**
|
||||
* This method is called if your task should be stopped even before you've called
|
||||
* {@link #taskFinished(TaskParams, boolean)}.
|
||||
*
|
||||
* <p>This will happen if the requirements specified at schedule time are no longer met. For
|
||||
* example you may have requested WiFi with
|
||||
* {@link android.content.Task.Builder#setRequiredNetworkCapabilities(int)}, yet while your
|
||||
* task was executing the user toggled WiFi. Another example is if you had specified
|
||||
* {@link android.content.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
|
||||
* idle maintenance window. You are solely responsible for the behaviour of your application
|
||||
* upon receipt of this message; your app will likely start to misbehave if you ignore it. One
|
||||
* repercussion is that the system will cease to hold a wakelock for you.</p>
|
||||
*
|
||||
* <p>After you've done your clean-up you are still expected to call
|
||||
* {@link #taskFinished(TaskParams, boolean)} this will inform the TaskManager that all is well, and
|
||||
* allow you to reschedule your task as it is probably uncompleted. Until you call
|
||||
* taskFinished() you will not receive any newly scheduled tasks with the given task id as the
|
||||
* TaskManager will consider the task to be in an error state.</p>
|
||||
*
|
||||
* @param params Parameters specifying info about this task.
|
||||
* @return True to indicate to the TaskManager whether you'd like to reschedule this task based
|
||||
* on the criteria provided at task creation-time. False to drop the task. Regardless of the
|
||||
* value returned, your task must stop executing.
|
||||
*/
|
||||
public abstract boolean onStopTask(TaskParams params);
|
||||
|
||||
/**
|
||||
* Callback to inform the TaskManager you have completed execution. This can be called from any
|
||||
* thread, as it will ultimately be run on your application's main thread. When the system
|
||||
* receives this message it will release the wakelock being held.
|
||||
* <p>
|
||||
* You can specify post-execution behaviour to the scheduler here with <code>needsReschedule
|
||||
* </code>. This will apply a back-off timer to your task based on the default, or what was
|
||||
* set with {@link android.content.Task.Builder#setBackoffCriteria(long, int)}. The
|
||||
* original requirements are always honoured even for a backed-off task.
|
||||
* Note that a task running in idle mode will not be backed-off. Instead what will happen
|
||||
* is the task will be re-added to the queue and re-executed within a future idle
|
||||
* maintenance window.
|
||||
* </p>
|
||||
*
|
||||
* @param params Parameters specifying system-provided info about this task, this was given to
|
||||
* your application in {@link #onStartTask(TaskParams)}.
|
||||
* @param needsReschedule True if this task is complete, false if you want the TaskManager to
|
||||
* reschedule you.
|
||||
*/
|
||||
public final void taskFinished(TaskParams params, boolean needsReschedule) {
|
||||
ensureHandler();
|
||||
Message m = Message.obtain(mHandler, MSG_TASK_FINISHED, params);
|
||||
m.arg2 = needsReschedule ? 1 : 0;
|
||||
m.sendToTarget();
|
||||
}
|
||||
}
|
||||
400
core/java/android/content/Task.java
Normal file
400
core/java/android/content/Task.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
66
core/java/android/content/TaskManager.java
Normal file
66
core/java/android/content/TaskManager.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 java.util.List;
|
||||
|
||||
/**
|
||||
* Class for scheduling various types of tasks with the scheduling framework on the device.
|
||||
*
|
||||
* Get an instance of this class through {@link Context#getSystemService(String)}.
|
||||
*/
|
||||
public abstract class TaskManager {
|
||||
/*
|
||||
* Returned from {@link #schedule(Task)} when an invalid parameter was supplied. This can occur
|
||||
* if the run-time for your task is too short, or perhaps the system can't resolve the
|
||||
* requisite {@link TaskService} in your package.
|
||||
*/
|
||||
static final int RESULT_INVALID_PARAMETERS = -1;
|
||||
/**
|
||||
* Returned from {@link #schedule(Task)} if this application has made too many requests for
|
||||
* work over too short a time.
|
||||
*/
|
||||
// TODO: Determine if this is necessary.
|
||||
static final int RESULT_OVER_QUOTA = -2;
|
||||
|
||||
/*
|
||||
* @param task The task you wish scheduled. See {@link Task#TaskBuilder} for more detail on
|
||||
* the sorts of tasks you can schedule.
|
||||
* @return If >0, this int corresponds to the taskId of the successfully scheduled task.
|
||||
* Otherwise you have to compare the return value to the error codes defined in this class.
|
||||
*/
|
||||
public abstract int schedule(Task task);
|
||||
|
||||
/**
|
||||
* Cancel a task that is pending in the TaskManager.
|
||||
* @param taskId unique identifier for this task. Obtain this value from the tasks returned by
|
||||
* {@link #getAllPendingTasks()}.
|
||||
* @return
|
||||
*/
|
||||
public abstract void cancel(int taskId);
|
||||
|
||||
/**
|
||||
* Cancel all tasks that have been registered with the TaskManager by this package.
|
||||
*/
|
||||
public abstract void cancelAll();
|
||||
|
||||
/**
|
||||
* @return a list of all the tasks registered by this package that have not yet been executed.
|
||||
*/
|
||||
public abstract List<Task> getAllPendingTasks();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user