diff options
author | Dianne Hackborn <hackbod@google.com> | 2011-04-12 18:16:08 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2011-04-12 18:28:06 -0700 |
commit | 0c5001d776d56bae02a5cc2663286a125d99bc5e (patch) | |
tree | ea7458737297e313c454f18d672e2b997af13990 /core/java/android/app | |
parent | 26b05f7dc35f47bc62bf9630df288ae2d6e4657e (diff) | |
download | frameworks_base-0c5001d776d56bae02a5cc2663286a125d99bc5e.zip frameworks_base-0c5001d776d56bae02a5cc2663286a125d99bc5e.tar.gz frameworks_base-0c5001d776d56bae02a5cc2663286a125d99bc5e.tar.bz2 |
Add APIs to remove tasks.
You can remove sub-tasks inside of a task, or an entire task.
When removing an entire task, you can have its process killed
as well.
When the process is killed, any running services will get an
onTaskRemoved() callback for them to do cleanup before their
process is killed (and the service possibly restarted).
Or they can set a new android:stopWithTask attribute to just
have the service automatically (cleanly) stopped at this point.
Change-Id: I1891bc2da006fa53b99c52f9040f1145650e6808
Diffstat (limited to 'core/java/android/app')
-rw-r--r-- | core/java/android/app/ActivityManager.java | 61 | ||||
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 50 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 12 | ||||
-rw-r--r-- | core/java/android/app/ApplicationThreadNative.java | 6 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 6 | ||||
-rw-r--r-- | core/java/android/app/IApplicationThread.java | 4 | ||||
-rw-r--r-- | core/java/android/app/Service.java | 20 |
7 files changed, 142 insertions, 17 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index ebe403b..fca6868 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -205,13 +205,6 @@ public class ActivityManager { public static final int RECENT_IGNORE_UNAVAILABLE = 0x0002; /** - * Flag for use with {@link #getRecentTasks}: also return the thumbnail - * bitmap (if available) for each recent task. - * @hide - */ - public static final int TASKS_GET_THUMBNAILS = 0x0001000; - - /** * Return a list of the tasks that the user has recently launched, with * the most recent being first and older ones after in order. * @@ -241,7 +234,7 @@ public class ActivityManager { /** * Information you can retrieve about a particular task that is currently * "running" in the system. Note that a running task does not mean the - * given task actual has a process it is actively running in; it simply + * given task actually has a process it is actively running in; it simply * means that the user has gone to it and never closed it, but currently * the system may have killed its process and is only holding on to its * last state in order to restart it when the user returns. @@ -396,6 +389,55 @@ public class ActivityManager { return getRunningTasks(maxNum, 0, null); } + /** + * Remove some end of a task's activity stack that is not part of + * the main application. The selected activities will be finished, so + * they are no longer part of the main task. + * + * @param taskId The identifier of the task. + * @param subTaskIndex The number of the sub-task; this corresponds + * to the index of the thumbnail returned by {@link #getTaskThumbnails(int)}. + * @return Returns true if the sub-task was found and was removed. + * + * @hide + */ + public boolean removeSubTask(int taskId, int subTaskIndex) + throws SecurityException { + try { + return ActivityManagerNative.getDefault().removeSubTask(taskId, subTaskIndex); + } catch (RemoteException e) { + // System dead, we will be dead too soon! + return false; + } + } + + /** + * If set, the process of the root activity of the task will be killed + * as part of removing the task. + * @hide + */ + public static final int REMOVE_TASK_KILL_PROCESS = 0x0001; + + /** + * Completely remove the given task. + * + * @param taskId Identifier of the task to be removed. + * @param flags Additional operational flags. May be 0 or + * {@link #REMOVE_TASK_KILL_PROCESS}. + * @return Returns true if the given task was found and removed. + * + * @hide + */ + public boolean removeTask(int taskId, int flags) + throws SecurityException { + try { + return ActivityManagerNative.getDefault().removeTask(taskId, flags); + } catch (RemoteException e) { + // System dead, we will be dead too soon! + return false; + } + } + /** @hide */ public static class TaskThumbnails implements Parcelable { public Bitmap mainThumbnail; @@ -405,9 +447,6 @@ public class ActivityManager { /** @hide */ public IThumbnailRetriever retriever; - /** @hide Magic for ActivityManagerService. Not marshalled */ - public ArrayList<Bitmap> otherThumbnails; - public TaskThumbnails() { } diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index d41c2d0..4b09b34c 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1405,6 +1405,28 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeInt(result ? 1 : 0); return true; } + + case REMOVE_SUB_TASK_TRANSACTION: + { + data.enforceInterface(IActivityManager.descriptor); + int taskId = data.readInt(); + int subTaskIndex = data.readInt(); + boolean result = removeSubTask(taskId, subTaskIndex); + reply.writeNoException(); + reply.writeInt(result ? 1 : 0); + return true; + } + + case REMOVE_TASK_TRANSACTION: + { + data.enforceInterface(IActivityManager.descriptor); + int taskId = data.readInt(); + int fl = data.readInt(); + boolean result = removeTask(taskId, fl); + reply.writeNoException(); + reply.writeInt(result ? 1 : 0); + return true; + } } @@ -3162,6 +3184,34 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); return result; } + + public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeInt(taskId); + data.writeInt(subTaskIndex); + mRemote.transact(REMOVE_SUB_TASK_TRANSACTION, data, reply, 0); + reply.readException(); + boolean result = reply.readInt() != 0; + reply.recycle(); + data.recycle(); + return result; + } + + public boolean removeTask(int taskId, int flags) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeInt(taskId); + data.writeInt(flags); + mRemote.transact(REMOVE_TASK_TRANSACTION, data, reply, 0); + reply.readException(); + boolean result = reply.readInt() != 0; + reply.recycle(); + data.recycle(); + return result; + } private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 57a79a9..4dfba91 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -334,6 +334,7 @@ public final class ActivityThread { private static final class ServiceArgsData { IBinder token; + boolean taskRemoved; int startId; int flags; Intent args; @@ -534,10 +535,11 @@ public final class ActivityThread { queueOrSendMessage(H.UNBIND_SERVICE, s); } - public final void scheduleServiceArgs(IBinder token, int startId, + public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId, int flags ,Intent args) { ServiceArgsData s = new ServiceArgsData(); s.token = token; + s.taskRemoved = taskRemoved; s.startId = startId; s.flags = flags; s.args = args; @@ -2129,7 +2131,13 @@ public final class ActivityThread { if (data.args != null) { data.args.setExtrasClassLoader(s.getClassLoader()); } - int res = s.onStartCommand(data.args, data.flags, data.startId); + int res; + if (!data.taskRemoved) { + res = s.onStartCommand(data.args, data.flags, data.startId); + } else { + s.onTaskRemoved(data.args); + res = Service.START_TASK_REMOVED_COMPLETE; + } QueuedWork.waitToFinish(); diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index a82234e..0e511f2 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -219,6 +219,7 @@ public abstract class ApplicationThreadNative extends Binder { data.enforceInterface(IApplicationThread.descriptor); IBinder token = data.readStrongBinder(); + boolean taskRemoved = data.readInt() != 0; int startId = data.readInt(); int fl = data.readInt(); Intent args; @@ -227,7 +228,7 @@ public abstract class ApplicationThreadNative extends Binder } else { args = null; } - scheduleServiceArgs(token, startId, fl, args); + scheduleServiceArgs(token, taskRemoved, startId, fl, args); return true; } @@ -688,11 +689,12 @@ class ApplicationThreadProxy implements IApplicationThread { data.recycle(); } - public final void scheduleServiceArgs(IBinder token, int startId, + public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId, int flags, Intent args) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeStrongBinder(token); + data.writeInt(taskRemoved ? 1 : 0); data.writeInt(startId); data.writeInt(flags); if (args != null) { diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 5a15b08..bec697a 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -344,6 +344,10 @@ public interface IActivityManager extends IInterface { // Multi-user APIs public boolean switchUser(int userid) throws RemoteException; + + public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException; + + public boolean removeTask(int taskId, int flags) throws RemoteException; /* * Private non-Binder interfaces @@ -561,4 +565,6 @@ public interface IActivityManager extends IInterface { int START_ACTIVITIES_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+121; int ACTIVITY_SLEPT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+122; int SWITCH_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+123; + int REMOVE_SUB_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+124; + int REMOVE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+125; } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 55177a9..b29b088 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -73,8 +73,8 @@ public interface IApplicationThread extends IInterface { Intent intent, boolean rebind) throws RemoteException; void scheduleUnbindService(IBinder token, Intent intent) throws RemoteException; - void scheduleServiceArgs(IBinder token, int startId, int flags, Intent args) - throws RemoteException; + void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId, + int flags, Intent args) throws RemoteException; void scheduleStopService(IBinder token) throws RemoteException; static final int DEBUG_OFF = 0; static final int DEBUG_ON = 1; diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index 05b9781..c179b35 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -371,6 +371,13 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac public static final int START_REDELIVER_INTENT = 3; /** + * Special constant for reporting that we are done processing + * {@link #onTaskRemoved(Intent)}. + * @hide + */ + public static final int START_TASK_REMOVED_COMPLETE = 1000; + + /** * This flag is set in {@link #onStartCommand} if the Intent is a * re-delivery of a previously delivered intent, because the service * had previously returned {@link #START_REDELIVER_INTENT} but had been @@ -500,6 +507,19 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac } /** + * This is called if the service is currently running and the user has + * removed a task that comes from the service's application. If you have + * set {@link android.content.pm.ServiceInfo#FLAG_STOP_WITH_TASK ServiceInfo.FLAG_STOP_WITH_TASK} + * then you will not receive this callback; instead, the service will simply + * be stopped. + * + * @param rootIntent The original root Intent that was used to launch + * the task that is being removed. + */ + public void onTaskRemoved(Intent rootIntent) { + } + + /** * Stop the service, if it was previously started. This is the same as * calling {@link android.content.Context#stopService} for this particular service. * |