New activity launch mode - singleInstancePerTask
Adding a new activity launch mode `singleInstancePerTask` which is similar to singleTask that the activity is single instance and can only be created in task root, but still allowed to be created in multiple documents or tasks. Also adding meta-data support of apps that targeting on previous SDK. Bug: 175354896 Test: IntentTests Change-Id: I4ba3b2ba6d619677f03e67d3b7da1b5d2a79907f
This commit is contained in:
@@ -11719,6 +11719,7 @@ package android.content.pm {
|
||||
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_INSTANCE_PER_TASK = 4; // 0x4
|
||||
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
|
||||
|
||||
@@ -74,12 +74,28 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
|
||||
*/
|
||||
public static final int LAUNCH_SINGLE_INSTANCE = 3;
|
||||
/**
|
||||
* The launch mode style requested by the activity. From the
|
||||
* {@link android.R.attr#launchMode} attribute, one of
|
||||
* {@link #LAUNCH_MULTIPLE},
|
||||
* {@link #LAUNCH_SINGLE_TOP}, {@link #LAUNCH_SINGLE_TASK}, or
|
||||
* {@link #LAUNCH_SINGLE_INSTANCE}.
|
||||
* Constant corresponding to <code>singleInstancePerTask</code> in
|
||||
* the {@link android.R.attr#launchMode} attribute.
|
||||
*/
|
||||
public static final int LAUNCH_SINGLE_INSTANCE_PER_TASK = 4;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = "LAUNCH_", value = {
|
||||
LAUNCH_MULTIPLE,
|
||||
LAUNCH_SINGLE_TOP,
|
||||
LAUNCH_SINGLE_TASK,
|
||||
LAUNCH_SINGLE_INSTANCE,
|
||||
LAUNCH_SINGLE_INSTANCE_PER_TASK
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface LaunchMode {
|
||||
}
|
||||
|
||||
/**
|
||||
* The launch mode style requested by the activity. From the
|
||||
* {@link android.R.attr#launchMode} attribute.
|
||||
*/
|
||||
@LaunchMode
|
||||
public int launchMode;
|
||||
|
||||
/**
|
||||
|
||||
@@ -214,6 +214,7 @@ public class PackageParser {
|
||||
public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes";
|
||||
public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY =
|
||||
"android.activity_window_layout_affinity";
|
||||
public static final String METADATA_ACTIVITY_LAUNCH_MODE = "android.activity.launch_mode";
|
||||
|
||||
/**
|
||||
* Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.content.pm.parsing.component;
|
||||
|
||||
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
import static android.content.pm.parsing.component.ComponentParseUtils.flag;
|
||||
|
||||
@@ -23,6 +24,7 @@ import android.annotation.NonNull;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.parsing.ParsingPackage;
|
||||
import android.content.pm.parsing.ParsingPackageUtils;
|
||||
import android.content.pm.parsing.ParsingUtils;
|
||||
@@ -402,6 +404,16 @@ public class ParsedActivityUtils {
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAlias && activity.launchMode != LAUNCH_SINGLE_INSTANCE_PER_TASK
|
||||
&& activity.metaData != null && activity.metaData.containsKey(
|
||||
PackageParser.METADATA_ACTIVITY_LAUNCH_MODE)) {
|
||||
final String launchMode = activity.metaData.getString(
|
||||
PackageParser.METADATA_ACTIVITY_LAUNCH_MODE);
|
||||
if (launchMode != null && launchMode.equals("singleInstancePerTask")) {
|
||||
activity.launchMode = LAUNCH_SINGLE_INSTANCE_PER_TASK;
|
||||
}
|
||||
}
|
||||
|
||||
ParseResult<ActivityInfo.WindowLayout> layoutResult =
|
||||
resolveActivityWindowLayout(activity, input);
|
||||
if (layoutResult.isError()) {
|
||||
|
||||
@@ -825,6 +825,12 @@
|
||||
<a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
|
||||
Stack</a> document for more details about tasks.-->
|
||||
<enum name="singleInstance" value="3" />
|
||||
<!-- The activity can only be running as the root activity of the task, the first activity
|
||||
that created the task, and therefore there will only be one instance of this activity
|
||||
in a task. In constrast to the {@code singleTask} launch mode, this activity can be
|
||||
started in multiple instances in different tasks if the
|
||||
{@code FLAG_ACTIVITY_MULTIPLE_TASK} is set.-->
|
||||
<enum name="singleInstancePerTask" value="4" />
|
||||
</attr>
|
||||
|
||||
<!-- Specify the orientation an activity should be run in. If not
|
||||
|
||||
@@ -48,6 +48,7 @@ import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
|
||||
import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
|
||||
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
|
||||
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
|
||||
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK;
|
||||
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
|
||||
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
@@ -2093,7 +2094,8 @@ class ActivityStarter {
|
||||
mAddingToTask = true;
|
||||
} else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|
||||
|| isDocumentLaunchesIntoExisting(mLaunchFlags)
|
||||
|| isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
|
||||
|| isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK,
|
||||
LAUNCH_SINGLE_INSTANCE_PER_TASK)) {
|
||||
// In this situation we want to remove all activities from the task up to the one
|
||||
// being started. In most cases this means we are resetting the task to its initial
|
||||
// state.
|
||||
@@ -2261,6 +2263,12 @@ class ActivityStarter {
|
||||
&& !isLaunchModeOneOf(LAUNCH_SINGLE_TASK, LAUNCH_SINGLE_INSTANCE)
|
||||
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
|
||||
|
||||
if (mLaunchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK) {
|
||||
// Adding NEW_TASK flag for singleInstancePerTask launch mode activity, so that the
|
||||
// activity won't be launched in source record's task.
|
||||
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
|
||||
}
|
||||
|
||||
sendNewTaskResultRequestIfNeeded();
|
||||
|
||||
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
|
||||
@@ -2529,6 +2537,14 @@ class ActivityStarter {
|
||||
}
|
||||
}
|
||||
|
||||
if (intentActivity != null && mLaunchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK
|
||||
&& !intentActivity.getTask().getRootActivity().mActivityComponent.equals(
|
||||
mStartActivity.mActivityComponent)) {
|
||||
// The task could be selected due to same task affinity. Do not reuse the task while
|
||||
// starting the singleInstancePerTask activity if it is not the task root activity.
|
||||
intentActivity = null;
|
||||
}
|
||||
|
||||
if (intentActivity != null
|
||||
&& (mStartActivity.isActivityTypeHome() || intentActivity.isActivityTypeHome())
|
||||
&& intentActivity.getDisplayArea() != mPreferredTaskDisplayArea) {
|
||||
@@ -2715,6 +2731,10 @@ class ActivityStarter {
|
||||
return mode1 == mLaunchMode || mode2 == mLaunchMode;
|
||||
}
|
||||
|
||||
private boolean isLaunchModeOneOf(int mode1, int mode2, int mode3) {
|
||||
return mode1 == mLaunchMode || mode2 == mLaunchMode || mode3 == mLaunchMode;
|
||||
}
|
||||
|
||||
static boolean isDocumentLaunchesIntoExisting(int flags) {
|
||||
return (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
|
||||
(flags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0;
|
||||
|
||||
Reference in New Issue
Block a user