diff options
| -rw-r--r-- | api/current.txt | 5 | ||||
| -rw-r--r-- | core/java/android/content/Intent.java | 29 | ||||
| -rw-r--r-- | core/java/android/content/pm/ActivityInfo.java | 5 | ||||
| -rw-r--r-- | core/res/res/values/attrs_manifest.xml | 27 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ActivityStackSupervisor.java | 77 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/TaskRecord.java | 5 |
6 files changed, 78 insertions, 70 deletions
diff --git a/api/current.txt b/api/current.txt index 6cbcadceb07e..bd9f9906997d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -7533,12 +7533,12 @@ package android.content { field public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 4194304; // 0x400000 field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000 field public static final int FLAG_ACTIVITY_CLEAR_TOP = 67108864; // 0x4000000 - field public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 524288; // 0x80000 + field public static final deprecated int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 524288; // 0x80000 field public static final int FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS = 8388608; // 0x800000 field public static final int FLAG_ACTIVITY_FORWARD_RESULT = 33554432; // 0x2000000 field public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 1048576; // 0x100000 field public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 134217728; // 0x8000000 - field public static final int FLAG_ACTIVITY_NEW_DOCUMENT = 268959744; // 0x10080000 + field public static final int FLAG_ACTIVITY_NEW_DOCUMENT = 524288; // 0x80000 field public static final int FLAG_ACTIVITY_NEW_TASK = 268435456; // 0x10000000 field public static final int FLAG_ACTIVITY_NO_ANIMATION = 65536; // 0x10000 field public static final int FLAG_ACTIVITY_NO_HISTORY = 1073741824; // 0x40000000 @@ -7989,6 +7989,7 @@ package android.content.pm { field public static final android.os.Parcelable.Creator CREATOR; field public static final int DOCUMENT_LAUNCH_ALWAYS = 2; // 0x2 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 FLAG_ALLOW_TASK_REPARENTING = 64; // 0x40 field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8 diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index bd07470ee583..186c996568a5 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3712,30 +3712,8 @@ public class Intent implements Parcelable, Cloneable { */ public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 0x00100000; /** - * If set, this marks a point in the task's activity stack that should - * be cleared when the task is reset. That is, the next time the task - * is brought to the foreground with - * {@link #FLAG_ACTIVITY_RESET_TASK_IF_NEEDED} (typically as a result of - * the user re-launching it from home), this activity and all on top of - * it will be finished so that the user does not return to them, but - * instead returns to whatever activity preceeded it. - * - * <p>When this flag is assigned to the root activity all activities up - * to, but not including the root activity, will be cleared. This prevents - * this flag from being used to finish all activities in a task and thereby - * ending the task. - * - * <p>This is useful for cases where you have a logical break in your - * application. For example, an e-mail application may have a command - * to view an attachment, which launches an image view activity to - * display it. This activity should be part of the e-mail application's - * task, since it is a part of the task the user is involved in. However, - * if the user leaves that task, and later selects the e-mail app from - * home, we may like them to return to the conversation they were - * viewing, not the picture attachment, since that is confusing. By - * setting this flag when launching the image viewer, that viewer and - * any activities it starts will be removed the next time the user returns - * to mail. + * @deprecated As of API 21 this performs identically to + * {@link #FLAG_ACTIVITY_NEW_DOCUMENT} which should be used instead of this. */ public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 0x00080000; /** @@ -3762,8 +3740,7 @@ public class Intent implements Parcelable, Cloneable { * @see android.R.attr#documentLaunchMode * @see #FLAG_ACTIVITY_MULTIPLE_TASK */ - public static final int FLAG_ACTIVITY_NEW_DOCUMENT = - FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | FLAG_ACTIVITY_NEW_TASK; + public static final int FLAG_ACTIVITY_NEW_DOCUMENT = FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET; /** * If set, this flag will prevent the normal {@link android.app.Activity#onUserLeaveHint} * callback from occurring on the current frontmost activity before it is diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index cfe471265608..791e5aa46c7f 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -84,6 +84,11 @@ public class ActivityInfo extends ComponentInfo */ public static final int DOCUMENT_LAUNCH_ALWAYS = 2; /** + * Constant corresponding to <code>never</code> in + * the {@link android.R.attr#documentLaunchMode} attribute. + */ + public static final int DOCUMENT_LAUNCH_NEVER = 3; + /** * The document launch mode style requested by the activity. From the * {@link android.R.attr#documentLaunchMode} attribute, one of * {@link #DOCUMENT_LAUNCH_NONE}, {@link #DOCUMENT_LAUNCH_INTO_EXISTING}, diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 3a0f7670036e..814d8fc0c800 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -898,16 +898,22 @@ android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} to every Intent used to launch the activity. - <p>The documentLaunchMode attribute may be assigned one of three values, "none", - "intoExisting" and "always", described in detail below. For values other than - <code>none</code> the activity must be defined with - {@link android.R.attr#launchMode} <code>standard</code> or <code>singleTop</code>. + <p>The documentLaunchMode attribute may be assigned one of four values, "none", + "intoExisting", "always" and "never", described in detail below. For values other than + <code>none</code> and <code>never</code> the activity must be defined with + {@link android.R.attr#launchMode} <code>standard</code>. If this attribute is not specified, <code>none</code> will be used. Note that <code>none</code> can be overridden at run time if the Intent used - to launch it contains the flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}. + to launch it contains the flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT + Intent.FLAG_ACTIVITY_NEW_DOCUMENT}. Similarly <code>intoExisting</code> will be overridden by the flag - {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} combined with - {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}. --> + {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT + Intent.FLAG_ACTIVITY_NEW_DOCUMENT} combined with + {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK + Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. If the value of + documentLaunchModes is <code>never</code> then any use of +.........{@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT + Intent.FLAG_ACTIVITY_NEW_DOCUMENT} to launch this activity will be ignored. --> <attr name="documentLaunchMode"> <!-- The default mode, which will create a new task only when {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK @@ -931,6 +937,13 @@ and {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK Intent.FLAG_ACTIVITY_MULTIPLE_TASK} both set. --> <enum name="always" value="2" /> + <!-- This activity will not be launched into a new document even if the Intent contains + {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT + Intent.FLAG_ACTIVITY_NEW_DOCUMENT}. This gives the activity writer ultimate + control over how their activity is used. Note that applications prior to api + 21 will default to documentLaunchMode="none" so only activities that explicitly + opt out with <code>"never"</code> may do so. --> + <enum name="never" value="3" /> </attr> <!-- The maximum number of entries of tasks rooted at this activity in the recent task list. diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 0cc53d194f8e..35f8f31d23b0 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1243,7 +1243,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // to ensure that it is safe to do so. If the upcoming activity will also // be part of the voice session, we can only launch it if it has explicitly // said it supports the VOICE category, or it is a part of the calling app. - if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0 + if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) { try { if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(), @@ -1460,6 +1460,47 @@ public final class ActivityStackSupervisor implements DisplayListener { int launchFlags = intent.getFlags(); + if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && + (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || + r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK)) { + // We have a conflict between the Intent and the Activity manifest, manifest wins. + Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " + + "\"singleInstance\" or \"singleTask\""); + launchFlags &= + ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + } else { + switch (r.info.documentLaunchMode) { + case ActivityInfo.DOCUMENT_LAUNCH_NONE: + break; + case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING: + launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT; + break; + case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS: + launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT; + break; + case ActivityInfo.DOCUMENT_LAUNCH_NEVER: + launchFlags &= ~Intent.FLAG_ACTIVITY_MULTIPLE_TASK; + break; + } + } + + if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + // For whatever reason this activity is being launched into a new + // task... yet the caller has requested a result back. Well, that + // is pretty messed up, so instead immediately send back a cancel + // and let the new task continue launched as normal without a + // dependency on its originator. + Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result."); + r.resultTo.task.stack.sendActivityResultLocked(-1, + r.resultTo, r.resultWho, r.requestCode, + Activity.RESULT_CANCELED, null); + r.resultTo = null; + } + + if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) { + launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; + } + // We'll invoke onUserLeaving before onPause only if the launching // activity did not explicitly state that this is an automated launch. mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0; @@ -1490,20 +1531,6 @@ public final class ActivityStackSupervisor implements DisplayListener { } } - switch (r.info.documentLaunchMode) { - case ActivityInfo.DOCUMENT_LAUNCH_NONE: - break; - case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS: - intent.addFlags( - Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - launchFlags = intent.getFlags(); - break; - case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING: - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); - launchFlags = intent.getFlags(); - break; - } - final boolean newDocument = intent.isDocument(); if (sourceRecord == null) { // This activity is not being started from another... in this // case we -always- start a new task. @@ -1512,11 +1539,6 @@ public final class ActivityStackSupervisor implements DisplayListener { "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent); launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } - } else if (newDocument) { - if (r.launchMode != ActivityInfo.LAUNCH_MULTIPLE) { - Slog.w(TAG, "FLAG_ACTIVITY_NEW_DOCUMENT and launchMode != \"standard\""); - r.launchMode = ActivityInfo.LAUNCH_MULTIPLE; - } } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { // The original activity who is starting us is running as a single // instance... this new activity it is starting must go on its @@ -1555,18 +1577,7 @@ public final class ActivityStackSupervisor implements DisplayListener { sourceStack = null; } - if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { - // For whatever reason this activity is being launched into a new - // task... yet the caller has requested a result back. Well, that - // is pretty messed up, so instead immediately send back a cancel - // and let the new task continue launched as normal without a - // dependency on its originator. - Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result."); - r.resultTo.task.stack.sendActivityResultLocked(-1, - r.resultTo, r.resultWho, r.requestCode, - Activity.RESULT_CANCELED, null); - r.resultTo = null; - } + intent.setFlags(launchFlags); boolean addingToTask = false; boolean movedHome = false; @@ -1801,7 +1812,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // Should this be considered a new task? if (r.resultTo == null && !addingToTask - && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { if (isLockTaskModeViolation(reuseTask)) { Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r); return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 1df230e7bb68..79e2d9d095df 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -647,8 +647,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() || (r.intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) == - Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) { + if (!r.isPersistable() || (activityNdx > 0 && + (r.intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0)) { + // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET). break; } out.startTag(null, TAG_ACTIVITY); |