Activity a
of the A app is single task launch mode.
a
and launch another app, for example, B app.a.startActivity()
method.There are three phenomenons after doing the above operations.
a
is moved to the front, but the front task belongs to the B app.a
, because the task of Activity a
is moved to the front.We analyze it in different Android versions.
After the first operation, the task of app B is on the top of task of A app. In startActivityUncheckedLocked()
method, when the launch mode is single task or single instance, there is following code.
// Android 4.3
// com/android/server/am/ActivityStack.java
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// If the target task is not in the front, then we need
// to bring it to the front... except... well, with
// SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
// to have the same behavior as if a new instance was
// being started, which means not bringing it to the front
// if the caller is not itself in the front.
ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
if (curTop != null && curTop.task != taskTop.task) {
boolean callerAtFront = sourceRecord == null
|| curTop.task == sourceRecord.task;
if (callerAtFront) {
// We really do want to push this one into the
// user's face, right now.
movedHome = true;
moveHomeToFrontFromLaunchLocked(launchFlags);
moveTaskToFrontLocked(taskTop.task, r, options);
options = null;
}}}}
If the caller is at the top, call moveTaskToFrontLocked()
method, that is to say the task of app A will be moved to the front.
In our case, we call startActivity()
method in Activity class, and this calls startActivityForResult()
method, so the sourceRecord.task
is the task of app A. And the curTop.task
is the task of home(in second step, we go home first.), then callerAtFront
is false, so moveTaskToFrontLocked()
method will not be called. Therefore, nothing will happen.
In Android 4.4, the code is following. Calling moveHomeStack()
method before if
statement is the difference from Android 4.3.
// Android 4.4
// com/android/server/am/ActivityStackSupervisor.java
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, int startFlags, boolean doResume,
Bundle options) {
if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
moveHomeStack(targetStack.isHomeStack());
ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
final ActivityStack lastStack = getLastStack();
if (curTop != null && (curTop.task != intentActivity.task ||
curTop.task != lastStack.topTask())) {
if (sourceRecord == null || (sourceStack.topActivity() != null &&
sourceStack.topActivity().task == sourceRecord.task)) {
movedHome = true;
targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);
}}}}
In our case, after calling moveHomeStack()
, the stack of app A, it is also the stack of app B, is moved to the front, and it does not call moveTaskToFrontLocked()
method. Therefore, the stack of app A is at the front, but the task of app B is at the front of the stack.
In the perspective of user, the app B is launched, although the activity of A is started.