Fix persistent tasks and expand scope
- Fixed missing tag closure on the xml for storing Intent categories. - Shortened timeout for flushing tasks to persistent storage from one minute to ten seconds. - Made persistency the default except for those tasks on the home stack and those tasks that exclude themselves from the recent task list. - Fixed deletion of tasks after restoring. Tasks now survive a second reboot, not just the first reboot. - Fixed sort order so most recent tasks will be restored at front. Fixes bug 15672002. Change-Id: I16d87d58c6fd2e879cfd0c0b18b2694432a79b71
This commit is contained in:
@ -885,7 +885,7 @@ package android {
|
||||
field public static final int permissionFlags = 16843719; // 0x10103c7
|
||||
field public static final int permissionGroup = 16842762; // 0x101000a
|
||||
field public static final int permissionGroupFlags = 16843717; // 0x10103c5
|
||||
field public static final int persistable = 16843823; // 0x101042f
|
||||
field public static final int persistableMode = 16843823; // 0x101042f
|
||||
field public static final int persistent = 16842765; // 0x101000d
|
||||
field public static final int persistentDrawingCache = 16842990; // 0x10100ee
|
||||
field public static final deprecated int phoneNumber = 16843111; // 0x1010167
|
||||
@ -8041,6 +8041,7 @@ package android.content.pm {
|
||||
field public static final int DOCUMENT_LAUNCH_INTO_EXISTING = 1; // 0x1
|
||||
field public static final int DOCUMENT_LAUNCH_NEVER = 3; // 0x3
|
||||
field public static final int DOCUMENT_LAUNCH_NONE = 0; // 0x0
|
||||
field public static final int DO_NOT_PERSIST = 1; // 0x1
|
||||
field public static final int FLAG_ALLOW_TASK_REPARENTING = 64; // 0x40
|
||||
field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
|
||||
field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
|
||||
@ -8052,13 +8053,14 @@ package android.content.pm {
|
||||
field public static final int FLAG_IMMERSIVE = 2048; // 0x800
|
||||
field public static final int FLAG_MULTIPROCESS = 1; // 0x1
|
||||
field public static final int FLAG_NO_HISTORY = 128; // 0x80
|
||||
field public static final int FLAG_PERSISTABLE = 4096; // 0x1000
|
||||
field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
|
||||
field public static final int FLAG_STATE_NOT_NEEDED = 16; // 0x10
|
||||
field public static final int LAUNCH_MULTIPLE = 0; // 0x0
|
||||
field public static final int LAUNCH_SINGLE_INSTANCE = 3; // 0x3
|
||||
field public static final int LAUNCH_SINGLE_TASK = 2; // 0x2
|
||||
field public static final int LAUNCH_SINGLE_TOP = 1; // 0x1
|
||||
field public static final int PERSIST_ACROSS_REBOOTS = 2; // 0x2
|
||||
field public static final int PERSIST_ROOT_ONLY = 0; // 0x0
|
||||
field public static final int SCREEN_ORIENTATION_BEHIND = 3; // 0x3
|
||||
field public static final int SCREEN_ORIENTATION_FULL_SENSOR = 10; // 0xa
|
||||
field public static final int SCREEN_ORIENTATION_FULL_USER = 13; // 0xd
|
||||
@ -8083,6 +8085,7 @@ package android.content.pm {
|
||||
field public int maxRecents;
|
||||
field public java.lang.String parentActivityName;
|
||||
field public java.lang.String permission;
|
||||
field public int persistableMode;
|
||||
field public int screenOrientation;
|
||||
field public int softInputMode;
|
||||
field public java.lang.String targetActivity;
|
||||
|
@ -929,7 +929,8 @@ public class Activity extends ContextThemeWrapper
|
||||
|
||||
/**
|
||||
* Same as {@link #onCreate(android.os.Bundle)} but called for those activities created with
|
||||
* the attribute {@link android.R.attr#persistable} set true.
|
||||
* the attribute {@link android.R.attr#persistableMode} set to
|
||||
* <code>persistAcrossReboots</code>.
|
||||
*
|
||||
* @param savedInstanceState if the activity is being re-initialized after
|
||||
* previously being shut down then this Bundle contains the data it most
|
||||
@ -1012,8 +1013,9 @@ public class Activity extends ContextThemeWrapper
|
||||
|
||||
/**
|
||||
* This is the same as {@link #onRestoreInstanceState(Bundle)} but is called for activities
|
||||
* created with the attribute {@link android.R.attr#persistable}. The {@link
|
||||
* android.os.PersistableBundle} passed came from the restored PersistableBundle first
|
||||
* created with the attribute {@link android.R.attr#persistableMode} set to
|
||||
* <code>persistAcrossReboots</code>. The {@link android.os.PersistableBundle} passed
|
||||
* came from the restored PersistableBundle first
|
||||
* saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}.
|
||||
*
|
||||
* <p>This method is called between {@link #onStart} and
|
||||
@ -1111,7 +1113,8 @@ public class Activity extends ContextThemeWrapper
|
||||
|
||||
/**
|
||||
* This is the same as {@link #onPostCreate(Bundle)} but is called for activities
|
||||
* created with the attribute {@link android.R.attr#persistable}.
|
||||
* created with the attribute {@link android.R.attr#persistableMode} set to
|
||||
* <code>persistAcrossReboots</code>.
|
||||
*
|
||||
* @param savedInstanceState The data most recently supplied in {@link #onSaveInstanceState}
|
||||
* @param persistentState The data caming from the PersistableBundle first
|
||||
@ -1352,10 +1355,10 @@ public class Activity extends ContextThemeWrapper
|
||||
|
||||
/**
|
||||
* This is the same as {@link #onSaveInstanceState} but is called for activities
|
||||
* created with the attribute {@link android.R.attr#persistable}. The {@link
|
||||
* android.os.PersistableBundle} passed in will be saved and presented in
|
||||
* {@link #onCreate(Bundle, PersistableBundle)} the first time that this activity
|
||||
* is restarted following the next device reboot.
|
||||
* created with the attribute {@link android.R.attr#persistableMode} set to
|
||||
* <code>persistAcrossReboots</code>. The {@link android.os.PersistableBundle} passed
|
||||
* in will be saved and presented in {@link #onCreate(Bundle, PersistableBundle)}
|
||||
* the first time that this activity is restarted following the next device reboot.
|
||||
*
|
||||
* @param outState Bundle in which to place your saved state.
|
||||
* @param outPersistentState State which will be saved across reboots.
|
||||
|
@ -317,7 +317,7 @@ public final class ActivityThread {
|
||||
}
|
||||
|
||||
public boolean isPersistable() {
|
||||
return (activityInfo.flags & ActivityInfo.FLAG_PERSISTABLE) != 0;
|
||||
return activityInfo.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
@ -7375,6 +7375,7 @@ public class Intent implements Parcelable, Cloneable {
|
||||
for (int categoryNdx = mCategories.size() - 1; categoryNdx >= 0; --categoryNdx) {
|
||||
out.attribute(null, ATTR_CATEGORY, mCategories.valueAt(categoryNdx));
|
||||
}
|
||||
out.endTag(null, TAG_CATEGORIES);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,6 +103,28 @@ public class ActivityInfo extends ComponentInfo
|
||||
*/
|
||||
public int documentLaunchMode;
|
||||
|
||||
/**
|
||||
* Constant corresponding to <code>persistRootOnly</code> in
|
||||
* the {@link android.R.attr#persistableMode} attribute.
|
||||
*/
|
||||
public static final int PERSIST_ROOT_ONLY = 0;
|
||||
/**
|
||||
* Constant corresponding to <code>doNotPersist</code> in
|
||||
* the {@link android.R.attr#persistableMode} attribute.
|
||||
*/
|
||||
public static final int DO_NOT_PERSIST = 1;
|
||||
/**
|
||||
* Constant corresponding to <code>persistAcrossReboots</code> in
|
||||
* the {@link android.R.attr#persistableMode} attribute.
|
||||
*/
|
||||
public static final int PERSIST_ACROSS_REBOOTS = 2;
|
||||
/**
|
||||
* Value indicating how this activity is to be persisted across
|
||||
* reboots for restoring in the Recents list.
|
||||
* {@link android.R.attr#persistableMode}
|
||||
*/
|
||||
public int persistableMode;
|
||||
|
||||
/**
|
||||
* The maximum number of tasks rooted at this activity that can be in the recent task list.
|
||||
* Refer to {@link android.R.attr#maxRecents}.
|
||||
@ -229,12 +251,6 @@ public class ActivityInfo extends ComponentInfo
|
||||
* @see android.app.Activity#setImmersive(boolean)
|
||||
*/
|
||||
public static final int FLAG_IMMERSIVE = 0x0800;
|
||||
/**
|
||||
* Bit in {@link #flags} indicating that this activity is to be persisted across
|
||||
* reboots for display in the Recents list.
|
||||
* {@link android.R.attr#persistable}
|
||||
*/
|
||||
public static final int FLAG_PERSISTABLE = 0x1000;
|
||||
/**
|
||||
* Bit in {@link #flags} indicating that tasks started with this activity are to be
|
||||
* removed from the recent list of tasks when the last activity in the task is finished.
|
||||
@ -641,13 +657,23 @@ public class ActivityInfo extends ComponentInfo
|
||||
return theme != 0 ? theme : applicationInfo.theme;
|
||||
}
|
||||
|
||||
private String persistableModeToString() {
|
||||
switch(persistableMode) {
|
||||
case PERSIST_ROOT_ONLY: return "PERSIST_ROOT_ONLY";
|
||||
case DO_NOT_PERSIST: return "DO_NOT_PERSIST";
|
||||
case PERSIST_ACROSS_REBOOTS: return "PERSIST_ACROSS_REBOOTS";
|
||||
default: return "UNKNOWN=" + persistableMode;
|
||||
}
|
||||
}
|
||||
|
||||
public void dump(Printer pw, String prefix) {
|
||||
super.dumpFront(pw, prefix);
|
||||
if (permission != null) {
|
||||
pw.println(prefix + "permission=" + permission);
|
||||
}
|
||||
pw.println(prefix + "taskAffinity=" + taskAffinity
|
||||
+ " targetActivity=" + targetActivity);
|
||||
+ " targetActivity=" + targetActivity
|
||||
+ " persistableMode=" + persistableModeToString());
|
||||
if (launchMode != 0 || flags != 0 || theme != 0) {
|
||||
pw.println(prefix + "launchMode=" + launchMode
|
||||
+ " flags=0x" + Integer.toHexString(flags)
|
||||
@ -688,6 +714,7 @@ public class ActivityInfo extends ComponentInfo
|
||||
dest.writeInt(softInputMode);
|
||||
dest.writeInt(uiOptions);
|
||||
dest.writeString(parentActivityName);
|
||||
dest.writeInt(persistableMode);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<ActivityInfo> CREATOR
|
||||
@ -713,5 +740,6 @@ public class ActivityInfo extends ComponentInfo
|
||||
softInputMode = source.readInt();
|
||||
uiOptions = source.readInt();
|
||||
parentActivityName = source.readString();
|
||||
persistableMode = source.readInt();
|
||||
}
|
||||
}
|
||||
|
@ -2524,10 +2524,9 @@ public class PackageParser {
|
||||
com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
|
||||
0);
|
||||
|
||||
if (sa.getBoolean(
|
||||
com.android.internal.R.styleable.AndroidManifestActivity_persistable, false)) {
|
||||
a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
|
||||
}
|
||||
a.info.persistableMode = sa.getInteger(
|
||||
com.android.internal.R.styleable.AndroidManifestActivity_persistableMode,
|
||||
ActivityInfo.PERSIST_ROOT_ONLY);
|
||||
|
||||
if (sa.getBoolean(
|
||||
com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
|
||||
|
@ -873,17 +873,33 @@
|
||||
<!-- The name of the logical parent of the activity as it appears in the manifest. -->
|
||||
<attr name="parentActivityName" format="string" />
|
||||
|
||||
<!-- Define an activity that will persist across reboots. If such an activity is in the
|
||||
Recents list when the device is shut off it will appear in the Recents list when
|
||||
the device is next powered on. To be persisted all activities in the task from the
|
||||
root activity up to the last activity before a <em>break</em> must be declared with
|
||||
the persistable attribute. A <em>break</em> is the first activity after the root
|
||||
started with Intent.FLAG_CLEAR_TASK_WHEN_RESET.
|
||||
<!-- Define how an activity persist across reboots. Activities defined as "never" will not
|
||||
be persisted. Those defined as "always" will be persisted. Those defined as "taskOnly"
|
||||
will persist the root activity of the task only. See below for more detail as to
|
||||
what gets persisted. -->
|
||||
<attr name="persistableMode">
|
||||
<!-- The default. If this activity forms the root of a task then that task will be
|
||||
persisted across reboots but only the launching intent will be used. All
|
||||
activities above this activity in the task will not be persisted. In addition
|
||||
this activity will not be passed a PersistableBundle into which it could have
|
||||
stored its state. -->
|
||||
<enum name="persistRootOnly" value="0" />
|
||||
<!-- If this activity forms the root of a task then that task will not be persisted
|
||||
across reboots -->
|
||||
<enum name="doNotPersist" value="1" />
|
||||
<!-- If this activity forms the root of a task then the task and this activity will
|
||||
be persisted across reboots. If the activity above this activity is also
|
||||
tagged with the attribute <code>"persist"</code> then it will be persisted as well.
|
||||
And so on up the task stack until either an activity without the
|
||||
<code>persistableMode="persistAcrossReboots"</code> attribute or one that was launched
|
||||
with the flag Intent.FLAG_CLEAR_TASK_WHEN_RESET is encountered.
|
||||
|
||||
<p>Activities that are declared with the persistable attribute will be provided with a
|
||||
forced-persistable Bundle in onCreate() and onSavedInstanceState(), and must only
|
||||
be passed a persistable Bundle in their Intent.extras. -->
|
||||
<attr name="persistable" format="boolean" />
|
||||
<p>Activities that are declared with the persistAcrossReboots attribute will be
|
||||
provided with a PersistableBundle in onSavedInstanceState(), These activities may
|
||||
use this PeristableBundle to save their state. Then, following a reboot, that
|
||||
PersistableBundle will be provided back to the activity in its onCreate() method. -->
|
||||
<enum name="persistAcrossReboots" value="2" />
|
||||
</attr>
|
||||
|
||||
<!-- This attribute specifies that an activity shall become the root activity of a
|
||||
new task each time it is launched. Using this attribute permits the user to
|
||||
@ -1623,7 +1639,7 @@
|
||||
<!-- @hide This broacast receiver will only receive broadcasts for the
|
||||
primary user. Can only be used with receivers. -->
|
||||
<attr name="primaryUserOnly" format="boolean" />
|
||||
<attr name="persistable" />
|
||||
<attr name="persistableMode" />
|
||||
<attr name="allowEmbedded" />
|
||||
<attr name="documentLaunchMode" />
|
||||
<attr name="maxRecents" />
|
||||
|
@ -2136,7 +2136,7 @@
|
||||
<public type="attr" name="colorControlActivated" />
|
||||
<public type="attr" name="colorButtonNormal" />
|
||||
<public type="attr" name="colorControlHighlight" />
|
||||
<public type="attr" name="persistable" />
|
||||
<public type="attr" name="persistableMode" />
|
||||
<public type="attr" name="titleTextAppearance" />
|
||||
<public type="attr" name="subtitleTextAppearance" />
|
||||
<public type="attr" name="slideEdge" />
|
||||
|
@ -568,7 +568,10 @@ final class ActivityRecord {
|
||||
}
|
||||
|
||||
boolean isPersistable() {
|
||||
return (info.flags & ActivityInfo.FLAG_PERSISTABLE) != 0;
|
||||
return (info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY ||
|
||||
info.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS) &&
|
||||
(intent == null ||
|
||||
(intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
|
||||
}
|
||||
|
||||
void makeFinishing() {
|
||||
|
@ -45,7 +45,7 @@ public class TaskPersister {
|
||||
static final boolean DEBUG = false;
|
||||
|
||||
/** When in slow mode don't write tasks out faster than this */
|
||||
private static final long INTER_TASK_DELAY_MS = 60000;
|
||||
private static final long INTER_TASK_DELAY_MS = 10000;
|
||||
private static final long DEBUG_INTER_TASK_DELAY_MS = 5000;
|
||||
|
||||
private static final String RECENTS_FILENAME = "_task";
|
||||
@ -69,6 +69,7 @@ public class TaskPersister {
|
||||
TaskPersister(File systemDir, ActivityStackSupervisor stackSupervisor) {
|
||||
sTasksDir = new File(systemDir, TASKS_DIRNAME);
|
||||
if (!sTasksDir.exists()) {
|
||||
if (DEBUG) Slog.d(TAG, "Creating tasks directory " + sTasksDir);
|
||||
if (!sTasksDir.mkdir()) {
|
||||
Slog.e(TAG, "Failure creating tasks directory " + sTasksDir);
|
||||
}
|
||||
@ -76,6 +77,7 @@ public class TaskPersister {
|
||||
|
||||
sImagesDir = new File(systemDir, IMAGES_DIRNAME);
|
||||
if (!sImagesDir.exists()) {
|
||||
if (DEBUG) Slog.d(TAG, "Creating images directory " + sTasksDir);
|
||||
if (!sImagesDir.mkdir()) {
|
||||
Slog.e(TAG, "Failure creating images directory " + sImagesDir);
|
||||
}
|
||||
@ -172,14 +174,15 @@ public class TaskPersister {
|
||||
TaskRecord.restoreFromXml(in, mStackSupervisor);
|
||||
if (DEBUG) Slog.d(TAG, "restoreTasksLocked: restored task=" + task);
|
||||
if (task != null) {
|
||||
task.isPersistable = true;
|
||||
tasks.add(task);
|
||||
final int taskId = task.taskId;
|
||||
recoveredTaskIds.add(taskId);
|
||||
mStackSupervisor.setNextTaskId(taskId);
|
||||
}
|
||||
} else {
|
||||
Slog.e(TAG, "restoreTasksLocked Unknown xml event=" + event + " name="
|
||||
+ name);
|
||||
Slog.wtf(TAG, "restoreTasksLocked Unknown xml event=" + event +
|
||||
" name=" + name);
|
||||
}
|
||||
}
|
||||
XmlUtils.skipCurrentTag(in);
|
||||
@ -195,6 +198,7 @@ public class TaskPersister {
|
||||
}
|
||||
}
|
||||
if (!DEBUG && deleteFile) {
|
||||
if (DEBUG) Slog.d(TAG, "Deleting file=" + taskFile.getName());
|
||||
taskFile.delete();
|
||||
}
|
||||
}
|
||||
@ -209,7 +213,7 @@ public class TaskPersister {
|
||||
Arrays.sort(tasksArray, new Comparator<TaskRecord>() {
|
||||
@Override
|
||||
public int compare(TaskRecord lhs, TaskRecord rhs) {
|
||||
final long diff = lhs.mLastTimeMoved - rhs.mLastTimeMoved;
|
||||
final long diff = rhs.mLastTimeMoved - lhs.mLastTimeMoved;
|
||||
if (diff < 0) {
|
||||
return -1;
|
||||
} else if (diff > 0) {
|
||||
@ -233,8 +237,7 @@ public class TaskPersister {
|
||||
try {
|
||||
taskId = Integer.valueOf(filename.substring(0, taskIdEnd));
|
||||
} catch (Exception e) {
|
||||
if (DEBUG) Slog.d(TAG, "removeObsoleteFile: Can't parse file=" +
|
||||
file.getName());
|
||||
Slog.wtf(TAG, "removeObsoleteFile: Can't parse file=" + file.getName());
|
||||
file.delete();
|
||||
continue;
|
||||
}
|
||||
@ -288,15 +291,18 @@ public class TaskPersister {
|
||||
synchronized(mService) {
|
||||
final ArrayList<TaskRecord> tasks = mService.mRecentTasks;
|
||||
persistentTaskIds.clear();
|
||||
if (DEBUG) Slog.d(TAG, "mRecents=" + tasks);
|
||||
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
|
||||
task = tasks.get(taskNdx);
|
||||
if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" +
|
||||
task.isPersistable + " needsPersisting=" + task.needsPersisting);
|
||||
if (task.isPersistable) {
|
||||
if (task.isPersistable && !task.stack.isHomeStack()) {
|
||||
if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
|
||||
persistentTaskIds.add(task.taskId);
|
||||
|
||||
if (task.needsPersisting) {
|
||||
try {
|
||||
if (DEBUG) Slog.d(TAG, "Saving task=" + task);
|
||||
stringWriter = saveToXml(task);
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
@ -305,6 +311,8 @@ public class TaskPersister {
|
||||
task.needsPersisting = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task=" + task);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -330,6 +338,8 @@ public class TaskPersister {
|
||||
// Made it through the entire list and didn't find anything new that needed
|
||||
// persisting.
|
||||
if (!DEBUG) {
|
||||
if (DEBUG) Slog.d(TAG, "Calling removeObsoleteFiles persistentTaskIds=" +
|
||||
persistentTaskIds);
|
||||
removeObsoleteFiles(persistentTaskIds);
|
||||
}
|
||||
|
||||
|
@ -652,8 +652,9 @@ final class TaskRecord extends ThumbnailHolder {
|
||||
final int numActivities = activities.size();
|
||||
for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
|
||||
final ActivityRecord r = activities.get(activityNdx);
|
||||
if (!r.isPersistable() || (activityNdx > 0 &&
|
||||
(r.intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0)) {
|
||||
if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
|
||||
((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) &&
|
||||
activityNdx > 0) {
|
||||
// Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
|
||||
break;
|
||||
}
|
||||
|
Reference in New Issue
Block a user