Launch activity behind launching task.
Use ActivityOptions.makeLaunchTaskBehindAnimation() to launch tasks
behind the current task. Includes animations for launching and
launched tasks.
Fixes bug 16157517.
Change-Id: I0a94af70b4748592e94673b958ee824cfb3d7ec0
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 543384f..8ef6dd6 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5655,6 +5655,11 @@
}
@Override
+ public final void notifyLaunchTaskBehindComplete(IBinder token) {
+ mStackSupervisor.scheduleLaunchTaskBehindComplete(token);
+ }
+
+ @Override
public String getCallingPackage(IBinder token) {
synchronized (this) {
ActivityRecord r = getCallingRecordLocked(token);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 46521c5..6c47922 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -167,6 +167,8 @@
ActivityContainer mInitialActivityContainer;
TaskDescription taskDescription; // the recents information for this activity
+ boolean mLaunchTaskBehind; // this activity is actively being launched with
+ // ActivityOptions.setLaunchTaskBehind, will be cleared once launch is completed.
void dump(PrintWriter pw, String prefix) {
final long now = SystemClock.uptimeMillis();
@@ -400,6 +402,7 @@
mInitialActivityContainer = container;
if (options != null) {
pendingOptions = new ActivityOptions(options);
+ mLaunchTaskBehind = pendingOptions.getLaunchTaskBehind();
}
// This starts out true, since the initial state of an activity
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 7e5cac7..32f2624 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1135,19 +1135,15 @@
return true;
}
- final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
- ActivityRecord r = topRunningActivityLocked(null);
- if (r != null) {
- ensureActivitiesVisibleLocked(r, starting, null, configChanges);
- }
- }
-
/**
* Make sure that all activities that need to be visible (that is, they
* currently can be seen by the user) actually are.
*/
- final void ensureActivitiesVisibleLocked(ActivityRecord top, ActivityRecord starting,
- String onlyThisProcess, int configChanges) {
+ final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
+ ActivityRecord top = topRunningActivityLocked(null);
+ if (top == null) {
+ return;
+ }
if (DEBUG_VISBILITY) Slog.v(
TAG, "ensureActivitiesVisible behind " + top
+ " configChanges=0x" + Integer.toHexString(configChanges));
@@ -1179,37 +1175,34 @@
continue;
}
aboveTop = false;
- if (!behindFullscreen) {
+ // mLaunchingBehind: Activities launching behind are at the back of the task stack
+ // but must be drawn initially for the animation as though they were visible.
+ if (!behindFullscreen || r.mLaunchTaskBehind) {
if (DEBUG_VISBILITY) Slog.v(
TAG, "Make visible? " + r + " finishing=" + r.finishing
+ " state=" + r.state);
- final boolean doThisProcess = onlyThisProcess == null
- || onlyThisProcess.equals(r.processName);
-
// First: if this is not the current activity being started, make
// sure it matches the current configuration.
- if (r != starting && doThisProcess) {
+ if (r != starting) {
ensureActivityConfigurationLocked(r, 0);
}
if (r.app == null || r.app.thread == null) {
- if (onlyThisProcess == null || onlyThisProcess.equals(r.processName)) {
- // This activity needs to be visible, but isn't even
- // running... get it started, but don't resume it
- // at this point.
- if (DEBUG_VISBILITY) Slog.v(TAG, "Start and freeze screen for " + r);
- if (r != starting) {
- r.startFreezingScreenLocked(r.app, configChanges);
- }
- if (!r.visible) {
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Starting and making visible: " + r);
- setVisibile(r, true);
- }
- if (r != starting) {
- mStackSupervisor.startSpecificActivityLocked(r, false, false);
- }
+ // This activity needs to be visible, but isn't even
+ // running... get it started, but don't resume it
+ // at this point.
+ if (DEBUG_VISBILITY) Slog.v(TAG, "Start and freeze screen for " + r);
+ if (r != starting) {
+ r.startFreezingScreenLocked(r.app, configChanges);
+ }
+ if (!r.visible || r.mLaunchTaskBehind) {
+ if (DEBUG_VISBILITY) Slog.v(
+ TAG, "Starting and making visible: " + r);
+ setVisibile(r, true);
+ }
+ if (r != starting) {
+ mStackSupervisor.startSpecificActivityLocked(r, false, false);
}
} else if (r.visible) {
@@ -1225,7 +1218,7 @@
}
} catch(RemoteException e) {
}
- } else if (onlyThisProcess == null) {
+ } else {
// This activity is not currently visible, but is running.
// Tell it to become visible.
r.visible = true;
@@ -1648,7 +1641,9 @@
} else {
mWindowManager.prepareAppTransition(prev.task == next.task
? AppTransition.TRANSIT_ACTIVITY_OPEN
- : AppTransition.TRANSIT_TASK_OPEN, false);
+ : next.mLaunchTaskBehind
+ ? AppTransition.TRANSIT_TASK_OPEN_BEHIND
+ : AppTransition.TRANSIT_TASK_OPEN, false);
}
}
if (false) {
@@ -1852,17 +1847,17 @@
mTaskHistory.remove(task);
// Now put task at top.
- int stackNdx = mTaskHistory.size();
+ int taskNdx = mTaskHistory.size();
if (!isCurrentProfileLocked(task.userId)) {
// Put non-current user tasks below current user tasks.
- while (--stackNdx >= 0) {
- if (!isCurrentProfileLocked(mTaskHistory.get(stackNdx).userId)) {
+ while (--taskNdx >= 0) {
+ if (!isCurrentProfileLocked(mTaskHistory.get(taskNdx).userId)) {
break;
}
}
- ++stackNdx;
+ ++taskNdx;
}
- mTaskHistory.add(stackNdx, task);
+ mTaskHistory.add(taskNdx, task);
updateTaskMovement(task, true);
}
@@ -1870,7 +1865,8 @@
boolean doResume, boolean keepCurTransition, Bundle options) {
TaskRecord rTask = r.task;
final int taskId = rTask.taskId;
- if (taskForIdLocked(taskId) == null || newTask) {
+ // mLaunchTaskBehind tasks get placed at the back of the task stack.
+ if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
// Last activity in task had been removed or ActivityManagerService is reusing task.
// Insert or replace.
// Might not even be in.
@@ -1895,7 +1891,8 @@
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
- r.userId, r.info.configChanges, task.voiceSession != null);
+ r.userId, r.info.configChanges, task.voiceSession != null,
+ r.mLaunchTaskBehind);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
@@ -1949,14 +1946,16 @@
mNoAnimActivities.add(r);
} else {
mWindowManager.prepareAppTransition(newTask
- ? AppTransition.TRANSIT_TASK_OPEN
+ ? r.mLaunchTaskBehind
+ ? AppTransition.TRANSIT_TASK_OPEN_BEHIND
+ : AppTransition.TRANSIT_TASK_OPEN
: AppTransition.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
mNoAnimActivities.remove(r);
}
mWindowManager.addAppToken(task.mActivities.indexOf(r),
r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
- r.info.configChanges, task.voiceSession != null);
+ r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
boolean doShow = true;
if (newTask) {
// Even though this activity is starting fresh, we still need
@@ -1972,7 +1971,12 @@
== ActivityOptions.ANIM_SCENE_TRANSITION) {
doShow = false;
}
- if (SHOW_APP_STARTING_PREVIEW && doShow) {
+ if (r.mLaunchTaskBehind) {
+ // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
+ // tell WindowManager that r is visible even though it is at the back of the stack.
+ mWindowManager.setAppVisibility(r.appToken, true);
+ ensureActivitiesVisibleLocked(null, 0);
+ } else if (SHOW_APP_STARTING_PREVIEW && doShow) {
// Figure out if we are transitioning from another activity that is
// "has the same starting icon" as the next one. This allows the
// window manager to keep the previous window it had previously
@@ -2003,7 +2007,7 @@
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
- r.info.configChanges, task.voiceSession != null);
+ r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
ActivityOptions.abort(options);
options = null;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index bc184c6..7c8dd81 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -144,6 +144,7 @@
static final int LOCK_TASK_END_MSG = FIRST_SUPERVISOR_STACK_MSG + 10;
static final int CONTAINER_CALLBACK_TASK_LIST_EMPTY = FIRST_SUPERVISOR_STACK_MSG + 11;
static final int CONTAINER_TASK_LIST_EMPTY_TIMEOUT = FIRST_SUPERVISOR_STACK_MSG + 12;
+ static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_STACK_MSG + 13;
private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay";
@@ -1557,9 +1558,9 @@
break;
}
}
- final int launchBehindFlags = Intent.FLAG_ACTIVITY_LAUNCH_BEHIND |
- Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
- final boolean affiliateTask = (launchFlags & launchBehindFlags) == launchBehindFlags;
+
+ final boolean launchTaskBehind = r.mLaunchTaskBehind &&
+ (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
// For whatever reason this activity is being launched into a new
@@ -1709,7 +1710,7 @@
sourceStack.topActivity().task == sourceRecord.task)) {
// We really do want to push this one into the
// user's face, right now.
- if (affiliateTask && sourceRecord != null) {
+ if (launchTaskBehind && sourceRecord != null) {
intentActivity.setTaskToAffiliateWith(sourceRecord.task);
}
movedHome = true;
@@ -1886,7 +1887,7 @@
boolean newTask = false;
boolean keepCurTransition = false;
- TaskRecord taskToAffiliate = affiliateTask && sourceRecord != null ?
+ TaskRecord taskToAffiliate = launchTaskBehind && sourceRecord != null ?
sourceRecord.task : null;
// Should this be considered a new task?
@@ -1898,12 +1899,15 @@
}
newTask = true;
targetStack = adjustStackFocus(r, newTask);
- targetStack.moveToFront();
+ if (!launchTaskBehind) {
+ targetStack.moveToFront();
+ }
if (reuseTask == null) {
r.setTask(targetStack.createTaskRecord(getNextTaskId(),
newTaskInfo != null ? newTaskInfo : r.info,
newTaskIntent != null ? newTaskIntent : intent,
- voiceSession, voiceInteractor, true), taskToAffiliate);
+ voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
+ taskToAffiliate);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
r.task);
} else {
@@ -1997,7 +2001,10 @@
ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
targetStack.mLastPausedActivity = null;
targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
- mService.setFocusedActivityLocked(r);
+ if (!launchTaskBehind) {
+ // Don't set focus on an activity that's going to the back.
+ mService.setFocusedActivityLocked(r);
+ }
return ActivityManager.START_SUCCESS;
}
@@ -2394,7 +2401,8 @@
mWindowManager.addAppToken(0, r.appToken, taskId, stackId,
r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
- r.userId, r.info.configChanges, task.voiceSession != null);
+ r.userId, r.info.configChanges, task.voiceSession != null,
+ r.mLaunchTaskBehind);
}
mWindowManager.addTask(taskId, stackId, false);
}
@@ -2642,6 +2650,19 @@
return true;
}
+ // Called when WindowManager has finished animating the launchingBehind activity to the back.
+ void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
+ r.mLaunchTaskBehind = false;
+ final TaskRecord task = r.task;
+ task.setLastThumbnail(task.stack.screenshotActivities(r));
+ mService.addRecentTaskLocked(task);
+ mWindowManager.setAppVisibility(r.appToken, false);
+ }
+
+ void scheduleLaunchTaskBehindComplete(IBinder token) {
+ mHandler.obtainMessage(LAUNCH_TASK_BEHIND_COMPLETE, token).sendToTarget();
+ }
+
void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
// First the front stacks. In case any are not fullscreen and are in front of home.
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
@@ -3293,6 +3314,14 @@
((ActivityContainer) msg.obj).onTaskListEmptyLocked();
}
} break;
+ case LAUNCH_TASK_BEHIND_COMPLETE: {
+ synchronized (mService) {
+ ActivityRecord r = ActivityRecord.forToken((IBinder) msg.obj);
+ if (r != null) {
+ handleLaunchTaskBehindCompleteLocked(r);
+ }
+ }
+ } break;
}
}
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index e007600..0e1340c 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -46,6 +46,8 @@
import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
+import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindBackgroundAnimation;
+import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation;
import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
@@ -72,44 +74,42 @@
WindowManagerService.DEBUG_APP_TRANSITIONS;
private static final boolean DEBUG_ANIM = WindowManagerService.DEBUG_ANIM;
- /** Bit mask that is set for all enter transition. */
- public static final int TRANSIT_ENTER_MASK = 0x1000;
-
- /** Bit mask that is set for all exit transitions. */
- public static final int TRANSIT_EXIT_MASK = 0x2000;
/** Not set up for a transition. */
public static final int TRANSIT_UNSET = -1;
/** No animation for transition. */
public static final int TRANSIT_NONE = 0;
/** A window in a new activity is being opened on top of an existing one in the same task. */
- public static final int TRANSIT_ACTIVITY_OPEN = 6 | TRANSIT_ENTER_MASK;
+ public static final int TRANSIT_ACTIVITY_OPEN = 6;
/** The window in the top-most activity is being closed to reveal the
* previous activity in the same task. */
- public static final int TRANSIT_ACTIVITY_CLOSE = 7 | TRANSIT_EXIT_MASK;
+ public static final int TRANSIT_ACTIVITY_CLOSE = 7;
/** A window in a new task is being opened on top of an existing one
* in another activity's task. */
- public static final int TRANSIT_TASK_OPEN = 8 | TRANSIT_ENTER_MASK;
+ public static final int TRANSIT_TASK_OPEN = 8;
/** A window in the top-most activity is being closed to reveal the
* previous activity in a different task. */
- public static final int TRANSIT_TASK_CLOSE = 9 | TRANSIT_EXIT_MASK;
+ public static final int TRANSIT_TASK_CLOSE = 9;
/** A window in an existing task is being displayed on top of an existing one
* in another activity's task. */
- public static final int TRANSIT_TASK_TO_FRONT = 10 | TRANSIT_ENTER_MASK;
+ public static final int TRANSIT_TASK_TO_FRONT = 10;
/** A window in an existing task is being put below all other tasks. */
- public static final int TRANSIT_TASK_TO_BACK = 11 | TRANSIT_EXIT_MASK;
+ public static final int TRANSIT_TASK_TO_BACK = 11;
/** A window in a new activity that doesn't have a wallpaper is being opened on top of one that
* does, effectively closing the wallpaper. */
- public static final int TRANSIT_WALLPAPER_CLOSE = 12 | TRANSIT_EXIT_MASK;
+ public static final int TRANSIT_WALLPAPER_CLOSE = 12;
/** A window in a new activity that does have a wallpaper is being opened on one that didn't,
* effectively opening the wallpaper. */
- public static final int TRANSIT_WALLPAPER_OPEN = 13 | TRANSIT_ENTER_MASK;
+ public static final int TRANSIT_WALLPAPER_OPEN = 13;
/** A window in a new activity is being opened on top of an existing one, and both are on top
* of the wallpaper. */
- public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14 | TRANSIT_ENTER_MASK;
+ public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14;
/** The window in the top-most activity is being closed to reveal the previous activity, and
* both are on top of the wallpaper. */
- public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15 | TRANSIT_EXIT_MASK;
+ public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15;
+ /** A window in a new task is being opened behind an existing one in another activity's task.
+ * The new window will show briefly and then be gone. */
+ public static final int TRANSIT_TASK_OPEN_BEHIND = 16;
/** Fraction of animation at which the recents thumbnail becomes completely transparent */
private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.25f;
@@ -811,6 +811,10 @@
? WindowAnimation_wallpaperIntraCloseEnterAnimation
: WindowAnimation_wallpaperIntraCloseExitAnimation;
break;
+ case TRANSIT_TASK_OPEN_BEHIND:
+ animAttr = enter
+ ? WindowAnimation_launchTaskBehindSourceAnimation
+ : WindowAnimation_launchTaskBehindBackgroundAnimation;
}
a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null;
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
@@ -896,9 +900,6 @@
case TRANSIT_NONE: {
return "TRANSIT_NONE";
}
- case TRANSIT_EXIT_MASK: {
- return "TRANSIT_EXIT_MASK";
- }
case TRANSIT_ACTIVITY_OPEN: {
return "TRANSIT_ACTIVITY_OPEN";
}
@@ -929,6 +930,9 @@
case TRANSIT_WALLPAPER_INTRA_CLOSE: {
return "TRANSIT_WALLPAPER_INTRA_CLOSE";
}
+ case TRANSIT_TASK_OPEN_BEHIND: {
+ return "TRANSIT_TASK_OPEN_BEHIND";
+ }
default: {
return "<UNKNOWN>";
}
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 63ae98e..874e105 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -16,7 +16,9 @@
package com.android.server.wm;
+import android.graphics.Bitmap;
import android.graphics.Matrix;
+import android.os.RemoteException;
import android.util.Slog;
import android.util.TimeUtils;
import android.view.Display;
@@ -281,9 +283,21 @@
final int N = mAllAppWinAnimators.size();
for (int i=0; i<N; i++) {
- mAllAppWinAnimators.get(i).finishExit();
+ final WindowStateAnimator winAnim = mAllAppWinAnimators.get(i);
+ if (mAppToken.mLaunchTaskBehind) {
+ winAnim.mWin.mExiting = true;
+ }
+ winAnim.finishExit();
}
- mAppToken.updateReportedVisibilityLocked();
+ if (mAppToken.mLaunchTaskBehind) {
+ try {
+ mService.mActivityManager.notifyLaunchTaskBehindComplete(mAppToken.token);
+ } catch (RemoteException e) {
+ }
+ mAppToken.mLaunchTaskBehind = false;
+ } else {
+ mAppToken.updateReportedVisibilityLocked();
+ }
return false;
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 12c15e2..312689b 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -109,6 +109,8 @@
boolean mDeferRemoval;
+ boolean mLaunchTaskBehind;
+
AppWindowToken(WindowManagerService _service, IApplicationToken _token,
boolean _voiceInteraction) {
super(_service, _token.asBinder(),
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 396ec8f..a5959d4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -497,8 +497,8 @@
boolean mStartingIconInTransition = false;
boolean mSkipAppTransitionAnimation = false;
- final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
- final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
+ final ArraySet<AppWindowToken> mOpeningApps = new ArraySet<AppWindowToken>();
+ final ArraySet<AppWindowToken> mClosingApps = new ArraySet<AppWindowToken>();
boolean mIsTouchDevice;
@@ -3234,6 +3234,12 @@
SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN);
}
+ if (atoken.mLaunchTaskBehind) {
+ // Differentiate the two animations. This one which is briefly on the screen
+ // gets the !enter animation, and the other activity which remains on the
+ // screen gets the enter animation. Both appear in the mOpeningApps set.
+ enter = false;
+ }
Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
mCurConfiguration.orientation, containingFrame, contentInsets, isFullScreen,
isVoiceInteraction);
@@ -3449,14 +3455,14 @@
EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
Task task = new Task(atoken, stack, userId);
mTaskIdToTask.put(taskId, task);
- stack.addTask(task, true);
+ stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */);
return task;
}
@Override
public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
- int configChanges, boolean voiceInteraction) {
+ int configChanges, boolean voiceInteraction, boolean launchTaskBehind) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3490,6 +3496,7 @@
atoken.requestedOrientation = requestedOrientation;
atoken.layoutConfigChanges = (configChanges &
(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
+ atoken.mLaunchTaskBehind = launchTaskBehind;
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
+ " to stack=" + stackId + " task=" + taskId + " at " + addPos);
@@ -3954,16 +3961,16 @@
}
synchronized(mWindowMap) {
- if (DEBUG_APP_TRANSITIONS) {
- RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
- Slog.w(TAG, "Execute app transition: " + mAppTransition, e);
- }
+ if (DEBUG_APP_TRANSITIONS) Slog.w(TAG, "Execute app transition: " + mAppTransition,
+ new RuntimeException("here").fillInStackTrace());
if (mAppTransition.isTransitionSet()) {
mAppTransition.setReady();
final long origId = Binder.clearCallingIdentity();
- performLayoutAndPlaceSurfacesLocked();
- Binder.restoreCallingIdentity(origId);
+ try {
+ performLayoutAndPlaceSurfacesLocked();
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
}
}
}
@@ -4370,17 +4377,11 @@
return;
}
- if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
- RuntimeException e = null;
- if (!HIDE_STACK_CRAWLS) {
- e = new RuntimeException();
- e.fillInStackTrace();
- }
- Slog.v(TAG, "setAppVisibility(" + token + ", visible=" + visible
- + "): " + mAppTransition
- + " hidden=" + wtoken.hidden
- + " hiddenRequested=" + wtoken.hiddenRequested, e);
- }
+ if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG, "setAppVisibility(" +
+ token + ", visible=" + visible + "): " + mAppTransition +
+ " hidden=" + wtoken.hidden + " hiddenRequested=" +
+ wtoken.hiddenRequested, HIDE_STACK_CRAWLS ?
+ null : new RuntimeException("here").fillInStackTrace());
// If we are preparing an app transition, then delay changing
// the visibility of this token until we execute that transition.
@@ -4428,6 +4429,21 @@
wtoken.waitingToHide = true;
}
}
+ if (mAppTransition.getAppTransition() == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
+ // We're launchingBehind, add the launching activity to mOpeningApps.
+ final WindowState win =
+ findFocusedWindowLocked(getDefaultDisplayContentLocked());
+ if (win != null) {
+ final AppWindowToken focusedToken = win.mAppToken;
+ if (focusedToken != null) {
+ if (DEBUG_APP_TRANSITIONS) Slog.d(TAG, "TRANSIT_TASK_OPEN_BEHIND, " +
+ " adding " + focusedToken + " to mOpeningApps");
+ // Force animation to be loaded.
+ focusedToken.hidden = true;
+ mOpeningApps.add(focusedToken);
+ }
+ }
+ }
return;
}
@@ -8558,7 +8574,7 @@
// all of the apps are ready. Otherwise just go because
// we'll unfreeze the display when everyone is ready.
for (i=0; i<NN && goodToGo; i++) {
- AppWindowToken wtoken = mOpeningApps.get(i);
+ AppWindowToken wtoken = mOpeningApps.valueAt(i);
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"Check opening app=" + wtoken + ": allDrawn="
+ wtoken.allDrawn + " startingDisplayed="
@@ -8631,12 +8647,12 @@
for (i=0; i<NN; i++) {
final AppWindowToken wtoken;
if (i < NC) {
- wtoken = mClosingApps.get(i);
+ wtoken = mClosingApps.valueAt(i);
if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
closingAppHasWallpaper = true;
}
} else {
- wtoken = mOpeningApps.get(i - NC);
+ wtoken = mOpeningApps.valueAt(i - NC);
if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
openingAppHasWallpaper = true;
}
@@ -8710,7 +8726,7 @@
NN = mOpeningApps.size();
for (i=0; i<NN; i++) {
- AppWindowToken wtoken = mOpeningApps.get(i);
+ AppWindowToken wtoken = mOpeningApps.valueAt(i);
final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
appAnimator.clearThumbnail();
@@ -8743,7 +8759,7 @@
}
NN = mClosingApps.size();
for (i=0; i<NN; i++) {
- AppWindowToken wtoken = mClosingApps.get(i);
+ AppWindowToken wtoken = mClosingApps.valueAt(i);
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
wtoken.mAppAnimator.clearThumbnail();
wtoken.inPendingTransaction = false;