summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java60
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java45
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java156
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java61
-rw-r--r--services/core/java/com/android/server/am/ActivityStartInterceptor.java4
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java134
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java38
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java85
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java239
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java57
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java21
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java48
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java308
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java249
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java13
21 files changed, 1028 insertions, 540 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b4ea49b9430d..81ba7a733225 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2849,7 +2849,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mTempConfig.setToDefaults();
mTempConfig.setLocales(LocaleList.getDefault());
mConfigurationSeq = mTempConfig.seq = 1;
- mStackSupervisor = new ActivityStackSupervisor(this);
+ mStackSupervisor = createStackSupervisor();
mStackSupervisor.onConfigurationChanged(mTempConfig);
mKeyguardController = mStackSupervisor.mKeyguardController;
mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
@@ -2897,6 +2897,10 @@ public class ActivityManagerService extends IActivityManager.Stub
Watchdog.getInstance().addThread(mHandler);
}
+ protected ActivityStackSupervisor createStackSupervisor() {
+ return new ActivityStackSupervisor(this, mHandler.getLooper());
+ }
+
public void setSystemServiceManager(SystemServiceManager mgr) {
mSystemServiceManager = mgr;
}
@@ -3151,7 +3155,8 @@ public class ActivityManagerService extends IActivityManager.Stub
* {@link ActivityStack#setResumedActivityLocked} when an activity is resumed.
*/
void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
- if (r.task.isApplicationTask()) {
+ final TaskRecord task = r.getTask();
+ if (task.isApplicationTask()) {
if (mCurAppTimeTracker != r.appTimeTracker) {
// We are switching app tracking. Complete the current one.
if (mCurAppTimeTracker != null) {
@@ -3174,17 +3179,18 @@ public class ActivityManagerService extends IActivityManager.Stub
// TODO: VI Maybe r.task.voiceInteractor || r.voiceInteractor != null
// TODO: Probably not, because we don't want to resume voice on switching
// back to this activity
- if (r.task.voiceInteractor != null) {
- startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid);
+ if (task.voiceInteractor != null) {
+ startRunningVoiceLocked(task.voiceSession, r.info.applicationInfo.uid);
} else {
finishRunningVoiceLocked();
if (mLastResumedActivity != null) {
final IVoiceInteractionSession session;
- if (mLastResumedActivity.task != null
- && mLastResumedActivity.task.voiceSession != null) {
- session = mLastResumedActivity.task.voiceSession;
+ final TaskRecord lastResumedActivityTask = mLastResumedActivity.getTask();
+ if (lastResumedActivityTask != null
+ && lastResumedActivityTask.voiceSession != null) {
+ session = lastResumedActivityTask.voiceSession;
} else {
session = mLastResumedActivity.voiceSession;
}
@@ -3317,7 +3323,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final void showAskCompatModeDialogLocked(ActivityRecord r) {
Message msg = Message.obtain();
msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG;
- msg.obj = r.task.askedCompatMode ? null : r;
+ msg.obj = r.getTask().askedCompatMode ? null : r;
mUiHandler.sendMessage(msg);
}
@@ -4723,7 +4729,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (ActivityRecord.forTokenLocked(callingActivity) != activity) {
throw new SecurityException("Only focused activity can call startVoiceInteraction");
}
- if (mRunningVoice != null || activity.task.voiceSession != null
+ if (mRunningVoice != null || activity.getTask().voiceSession != null
|| activity.voiceSession != null) {
Slog.w(TAG, "Already in a voice interaction, cannot start new voice interaction");
return;
@@ -5033,7 +5039,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return true;
}
// Keep track of the root activity of the task before we finish it
- TaskRecord tr = r.task;
+ TaskRecord tr = r.getTask();
ActivityRecord rootR = tr.getRootActivity();
if (rootR == null) {
Slog.w(TAG, "Finishing task with all activities already finished");
@@ -5170,7 +5176,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Do not allow task to finish if last task in lockTask mode. Launchable priv-apps
// can finish.
- final TaskRecord task = r.task;
+ final TaskRecord task = r.getTask();
if (task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV &&
mStackSupervisor.isLastLockedTask(task) && task.getRootActivity() == r) {
mStackSupervisor.showLockTaskToast();
@@ -7834,7 +7840,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return false;
}
// An activity is consider to be in multi-window mode if its task isn't fullscreen.
- return !r.task.mFullscreen;
+ return !r.getTask().mFullscreen;
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -9927,8 +9933,9 @@ public class ActivityManagerService extends IActivityManager.Stub
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
r.setTaskDescription(td);
- r.task.updateTaskDescription();
- mTaskChangeNotificationController.notifyTaskDescriptionChanged(r.task.taskId, td);
+ final TaskRecord task = r.getTask();
+ task.updateTaskDescription();
+ mTaskChangeNotificationController.notifyTaskDescriptionChanged(task.taskId, td);
}
}
}
@@ -10378,8 +10385,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (DEBUG_STACK) Slog.d(TAG_STACK, "exitFreeformMode: " + r);
- r.task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT,
- ANIMATE, !DEFER_RESUME, "exitFreeformMode");
+ r.getTask().reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP,
+ REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, "exitFreeformMode");
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -10760,7 +10767,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (r == null) {
return;
}
- final TaskRecord task = r.task;
+ final TaskRecord task = r.getTask();
if (task != null) {
startLockTaskModeLocked(task);
}
@@ -10859,7 +10866,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (r == null) {
return;
}
- mStackSupervisor.showLockTaskEscapeMessageLocked(r.task);
+ mStackSupervisor.showLockTaskEscapeMessageLocked(r.getTask());
}
}
@@ -13121,9 +13128,10 @@ public class ActivityManagerService extends IActivityManager.Stub
if (r == null) {
return false;
}
- int index = r.task.mActivities.lastIndexOf(r);
+ final TaskRecord task = r.getTask();
+ int index = task.mActivities.lastIndexOf(r);
if (index > 0) {
- ActivityRecord under = r.task.mActivities.get(index - 1);
+ ActivityRecord under = task.mActivities.get(index - 1);
under.returningOptions = ActivityOptions.fromBundle(options);
}
final boolean translucentChanged = r.changeWindowTranslucency(false);
@@ -13410,7 +13418,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (r == null) {
throw new IllegalArgumentException();
}
- return r.task.getTopActivity() == r;
+ return r.getTask().getTopActivity() == r;
}
}
@@ -15928,8 +15936,9 @@ public class ActivityManagerService extends IActivityManager.Stub
}
needSep = true;
synchronized (this) {
- if (lastTask != r.task) {
- lastTask = r.task;
+ final TaskRecord task = r.getTask();
+ if (lastTask != task) {
+ lastTask = task;
pw.print("TASK "); pw.print(lastTask.affinity);
pw.print(" id="); pw.print(lastTask.taskId);
pw.print(" userId="); pw.println(lastTask.userId);
@@ -20561,8 +20570,9 @@ public class ActivityManagerService extends IActivityManager.Stub
app.cached = false;
app.empty = false;
foregroundActivities = true;
- if (r.task != null && minLayer > 0) {
- final int layer = r.task.mLayerRank;
+ final TaskRecord task = r.getTask();
+ if (task != null && minLayer > 0) {
+ final int layer = task.mLayerRank;
if (layer >= 0 && minLayer > layer) {
minLayer = layer;
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index cbb51e1566c4..3a2941467cb6 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -229,7 +229,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
private int theme; // resource identifier of activity's theme.
private int realTheme; // actual theme resource we will use, never 0.
private int windowFlags; // custom window flags for preview window.
- TaskRecord task; // the task this is in.
+ private TaskRecord task; // the task this is in.
private long createTime = System.currentTimeMillis();
long displayStartTime; // when we started launching this activity
long fullyDrawnStartTime; // when we started launching this activity
@@ -686,9 +686,48 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
@Override
protected ConfigurationContainer getParent() {
+ return getTask();
+ }
+
+ TaskRecord getTask() {
return task;
}
+ /**
+ * Sets reference to the {@link TaskRecord} the {@link ActivityRecord} will treat as its parent.
+ * Note that this does not actually add the {@link ActivityRecord} as a {@link TaskRecord}
+ * children. However, this method will clean up references to this {@link ActivityRecord} in
+ * {@link ActivityStack}.
+ * @param task The new parent {@link TaskRecord}.
+ */
+ void setTask(TaskRecord task) {
+ setTask(task, false /*reparenting*/);
+ }
+
+ /**
+ * This method should only be called by {@link TaskRecord#removeActivity(ActivityRecord)}.
+ */
+ void setTask(TaskRecord task, boolean reparenting) {
+ // Do nothing if the {@link TaskRecord} is the same as the current {@link getTask}.
+ if (task != null && task == getTask()) {
+ return;
+ }
+
+ final ActivityStack stack = getStack();
+
+ // If the new {@link TaskRecord} is from a different {@link ActivityStack}, remove this
+ // {@link ActivityRecord} from its current {@link ActivityStack}.
+ if (!reparenting && stack != null && (task == null || stack != task.getStack())) {
+ stack.onActivityRemovedFromStack(this);
+ }
+
+ this.task = task;
+
+ if (!reparenting) {
+ onParentChanged();
+ }
+ }
+
static class Token extends IApplicationToken.Stub {
private final WeakReference<ActivityRecord> weakActivity;
@@ -925,8 +964,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
// Must reparent first in window manager
mWindowContainerController.reparent(newTask.getWindowContainerController(), position);
- // Remove the activity from the old task and add it to the new task
- prevTask.removeActivity(this);
+ // Remove the activity from the old task and add it to the new task.
+ prevTask.removeActivity(this, true /*reparenting*/);
newTask.addActivityAtIndex(position, this);
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 3d50b7cc729d..f13b11e65a88 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -116,6 +116,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.Watchdog;
@@ -725,7 +726,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (r == null) {
return null;
}
- final TaskRecord task = r.task;
+ final TaskRecord task = r.getTask();
final ActivityStack stack = r.getStack();
if (stack != null && task.mActivities.contains(r) && mTaskHistory.contains(task)) {
if (stack != this) Slog.w(TAG,
@@ -934,7 +935,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
+ taskIntent.getComponent().flattenToShortString()
- + "/aff=" + r.task.rootAffinity + " to new cls="
+ + "/aff=" + r.getTask().rootAffinity + " to new cls="
+ intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
// TODO Refactor to remove duplications. Check if logic can be simplified.
if (taskIntent != null && taskIntent.getComponent() != null &&
@@ -1049,8 +1050,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
void addRecentActivityLocked(ActivityRecord r) {
if (r != null) {
- mRecentTasks.addLocked(r.task);
- r.task.touchActiveTime();
+ final TaskRecord task = r.getTask();
+ mRecentTasks.addLocked(task);
+ task.touchActiveTime();
}
}
@@ -1226,11 +1228,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
prev.state = ActivityState.PAUSING;
- prev.task.touchActiveTime();
+ prev.getTask().touchActiveTime();
clearLaunchTime(prev);
final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
if (mService.mHasRecents
- && (next == null || next.noDisplay || next.task != prev.task || uiSleeping)) {
+ && (next == null || next.noDisplay || next.getTask() != prev.getTask()
+ || uiSleeping)) {
prev.mUpdateTaskThumbnailWhenHidden = true;
}
stopFullyDrawnTraceIfNeeded();
@@ -1457,7 +1460,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// Find the first visible activity above the passed activity and if it is translucent return it
// otherwise return null;
ActivityRecord findNextTranslucentActivity(ActivityRecord r) {
- TaskRecord task = r.task;
+ TaskRecord task = r.getTask();
if (task == null) {
return null;
}
@@ -1604,7 +1607,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// Otherwise, the docked stack is always visible, except in the case where the top
// running activity task in the focus stack doesn't support any form of resizing but we
// show it for the home task even though it's not resizable.
- final TaskRecord task = r != null ? r.task : null;
+ final TaskRecord task = r != null ? r.getTask() : null;
return task == null || task.supportsSplitScreen() || task.isHomeTask() ? STACK_VISIBLE
: STACK_INVISIBLE;
}
@@ -2157,8 +2160,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
mResumedActivity = r;
r.state = ActivityState.RESUMED;
mService.setResumedActivityUncheckLocked(r, reason);
- r.task.touchActiveTime();
- mRecentTasks.addLocked(r.task);
+ final TaskRecord task = r.getTask();
+ task.touchActiveTime();
+ mRecentTasks.addLocked(task);
}
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
@@ -2207,8 +2211,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
return false;
}
- final TaskRecord nextTask = next.task;
- final TaskRecord prevTask = prev != null ? prev.task : null;
+ final TaskRecord nextTask = next.getTask();
+ final TaskRecord prevTask = prev != null ? prev.getTask() : null;
if (prevTask != null && prevTask.getStack() == this &&
prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2373,7 +2377,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
anim = false;
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
} else {
- mWindowManager.prepareAppTransition(prev.task == next.task
+ mWindowManager.prepareAppTransition(prev.getTask() == next.getTask()
? TRANSIT_ACTIVITY_CLOSE
: TRANSIT_TASK_CLOSE, false);
}
@@ -2385,7 +2389,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
anim = false;
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
} else {
- mWindowManager.prepareAppTransition(prev.task == next.task
+ mWindowManager.prepareAppTransition(prev.getTask() == next.getTask()
? TRANSIT_ACTIVITY_OPEN
: next.mLaunchTaskBehind
? TRANSIT_TASK_OPEN_BEHIND
@@ -2522,7 +2526,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
next.notifyAppResumed(next.stopped, allowSavedSurface);
EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
- System.identityHashCode(next), next.task.taskId, next.shortComponentName);
+ System.identityHashCode(next), next.getTask().taskId,
+ next.shortComponentName);
next.sleeping = false;
mService.showUnsupportedZoomDialogIfNeededLocked(next);
@@ -2696,9 +2701,15 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
return;
}
- // If the task was launched from the assistant stack, set the return type to assistant
final ActivityStack lastStack = mStackSupervisor.getLastStack();
- if (lastStack != null && lastStack.isAssistantStack()) {
+
+ // If there is no last task, do not set task to return to
+ if (lastStack == null) {
+ return;
+ }
+
+ // If the task was launched from the assistant stack, set the return type to assistant
+ if (lastStack.isAssistantStack()) {
task.setTaskToReturnTo(ASSISTANT_ACTIVITY_TYPE);
return;
}
@@ -2721,7 +2732,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
- TaskRecord rTask = r.task;
+ TaskRecord rTask = r.getTask();
final int taskId = rTask.taskId;
// mLaunchTaskBehind tasks get placed at the back of the task stack.
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
@@ -2740,7 +2751,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// All activities in task are finishing.
continue;
}
- if (task == r.task) {
+ if (task == rTask) {
// Here it is! Now, if this is not yet visible to the
// user, then just add it without starting; it will
// get started when the user navigates back to it.
@@ -2762,13 +2773,14 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// If we are not placing the new activity frontmost, we do not want to deliver the
// onUserLeaving callback to the actual frontmost activity
- if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
+ final TaskRecord activityTask = r.getTask();
+ if (task == activityTask && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
mStackSupervisor.mUserLeaving = false;
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
"startActivity() behind front, mUserLeaving=false");
}
- task = r.task;
+ task = activityTask;
// Slot the activity into the history stack and proceed
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
@@ -2830,11 +2842,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// "has the same starting icon" as the next one. This allows the
// window manager to keep the previous window it had previously
// created, if it still had one.
- ActivityRecord prev = r.task.topRunningActivityWithStartingWindowLocked();
+ TaskRecord prevTask = r.getTask();
+ ActivityRecord prev = prevTask.topRunningActivityWithStartingWindowLocked();
if (prev != null) {
// We don't want to reuse the previous starting preview if:
// (1) The current activity is in a different task.
- if (prev.task != r.task) {
+ if (prev.getTask() != prevTask) {
prev = null;
}
// (2) The current activity is already displayed.
@@ -2853,7 +2866,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
private boolean isTaskSwitch(ActivityRecord r,
ActivityRecord topFocusedActivity) {
- return topFocusedActivity != null && r.task != topFocusedActivity.task;
+ return topFocusedActivity != null && r.getTask() != topFocusedActivity.getTask();
}
/**
@@ -2920,20 +2933,20 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
!mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ?
mTaskHistory.get(0).mActivities.get(0) : null;
if (bottom != null && target.taskAffinity != null
- && target.taskAffinity.equals(bottom.task.affinity)) {
+ && target.taskAffinity.equals(bottom.getTask().affinity)) {
// If the activity currently at the bottom has the
// same task affinity as the one we are moving,
// then merge it into the same task.
- targetTask = bottom.task;
+ targetTask = bottom.getTask();
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
- + " out to bottom task " + bottom.task);
+ + " out to bottom task " + targetTask);
} else {
targetTask = createTaskRecord(
mStackSupervisor.getNextTaskIdForUserLocked(target.userId),
target.info, null, null, null, false, target.mActivityType);
targetTask.affinityIntent = target.intent;
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
- + " out to new task " + target.task);
+ + " out to new task " + targetTask);
}
boolean noOptions = canMoveOptions;
@@ -2955,7 +2968,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
"Removing activity " + p + " from task=" + task + " adding to task="
+ targetTask + " Callers=" + Debug.getCallers(4));
if (DEBUG_TASKS) Slog.v(TAG_TASKS,
- "Pushing next activity " + p + " out to target's task " + target.task);
+ "Pushing next activity " + p + " out to target's task " + target);
p.reparent(targetTask, 0 /* position - bottom */, "resetTargetTaskIfNeeded");
}
@@ -3126,13 +3139,13 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
boolean forceReset =
(newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
if (ACTIVITY_INACTIVE_RESET_TIME > 0
- && taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
+ && taskTop.getTask().getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
if ((newActivity.info.flags & ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
forceReset = true;
}
}
- final TaskRecord task = taskTop.task;
+ final TaskRecord task = taskTop.getTask();
/** False until we evaluate the TaskRecord associated with taskTop. Switches to true
* for remaining tasks. Used for later tasks to reparent to task. */
@@ -3215,7 +3228,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// stack as long as there is a running activity.
return;
} else {
- final TaskRecord task = r.task;
+ final TaskRecord task = r.getTask();
final boolean isAssistantOrOverAssistant = task.getStack().isAssistantStack() ||
task.isOverAssistantStack();
if (r.frontOfTask && task == topTask() &&
@@ -3374,10 +3387,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
- int taskNdx = mTaskHistory.indexOf(r.task);
- int activityNdx = r.task.mActivities.indexOf(r);
+ finishedTask = r.getTask();
+ int taskNdx = mTaskHistory.indexOf(finishedTask);
+ final TaskRecord task = finishedTask;
+ int activityNdx = task.mActivities.indexOf(r);
finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
- finishedTask = r.task;
+ finishedTask = task;
// Also terminate any activities below it that aren't yet
// stopped, to avoid a situation where one will get
// re-start our crashing activity once it gets resumed again.
@@ -3447,7 +3462,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
final boolean finishActivityAffinityLocked(ActivityRecord r) {
- ArrayList<ActivityRecord> activities = r.task.mActivities;
+ ArrayList<ActivityRecord> activities = r.getTask().mActivities;
for (int index = activities.indexOf(r); index >= 0; --index) {
ActivityRecord cur = activities.get(index);
if (!Objects.equals(cur.taskAffinity, r.taskAffinity)) {
@@ -3512,7 +3527,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
mWindowManager.deferSurfaceLayout();
try {
r.makeFinishingLocked();
- final TaskRecord task = r.task;
+ final TaskRecord task = r.getTask();
EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
r.userId, System.identityHashCode(r),
task.taskId, r.shortComponentName, reason);
@@ -3701,23 +3716,24 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final boolean shouldUpRecreateTaskLocked(ActivityRecord srec, String destAffinity) {
// Basic case: for simple app-centric recents, we need to recreate
// the task if the affinity has changed.
- if (srec == null || srec.task.affinity == null ||
- !srec.task.affinity.equals(destAffinity)) {
+ if (srec == null || srec.getTask().affinity == null ||
+ !srec.getTask().affinity.equals(destAffinity)) {
return true;
}
// Document-centric case: an app may be split in to multiple documents;
// they need to re-create their task if this current activity is the root
// of a document, unless simply finishing it will return them to the the
// correct app behind.
- if (srec.frontOfTask && srec.task != null && srec.task.getBaseIntent() != null
- && srec.task.getBaseIntent().isDocument()) {
+ final TaskRecord task = srec.getTask();
+ if (srec.frontOfTask && task != null && task.getBaseIntent() != null
+ && task.getBaseIntent().isDocument()) {
// Okay, this activity is at the root of its task. What to do, what to do...
- if (srec.task.getTaskToReturnTo() != ActivityRecord.APPLICATION_ACTIVITY_TYPE) {
+ if (task.getTaskToReturnTo() != ActivityRecord.APPLICATION_ACTIVITY_TYPE) {
// Finishing won't return to an application, so we need to recreate.
return true;
}
// We now need to get the task below it to determine what to do.
- int taskIdx = mTaskHistory.indexOf(srec.task);
+ int taskIdx = mTaskHistory.indexOf(task);
if (taskIdx <= 0) {
Slog.w(TAG, "shouldUpRecreateTask: task not in history for " + srec);
return false;
@@ -3727,7 +3743,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
return true;
}
TaskRecord prevTask = mTaskHistory.get(taskIdx);
- if (!srec.task.affinity.equals(prevTask.affinity)) {
+ if (!task.affinity.equals(prevTask.affinity)) {
// These are different apps, so need to recreate.
return true;
}
@@ -3737,7 +3753,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
Intent resultData) {
- final TaskRecord task = srec.task;
+ final TaskRecord task = srec.getTask();
final ArrayList<ActivityRecord> activities = task.mActivities;
final int start = activities.indexOf(srec);
if (!mTaskHistory.contains(task) || (start < 0)) {
@@ -3816,6 +3832,22 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
Binder.restoreCallingIdentity(origId);
return foundParentInTask;
}
+
+ /**
+ * Remove any state associated with the {@link ActivityRecord}. This should be called whenever
+ * an activity moves away from the stack.
+ */
+ void onActivityRemovedFromStack(ActivityRecord r) {
+ if (mResumedActivity == r) {
+ mResumedActivity = null;
+ }
+ if (mPausingActivity == r) {
+ mPausingActivity = null;
+ }
+
+ removeTimeoutsForActivityLocked(r);
+ }
+
/**
* Perform the common clean-up of an activity record. This is called both
* as part of destroyActivityLocked() (when destroying the client-side
@@ -3826,12 +3858,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
* Note: Call before #removeActivityFromHistoryLocked.
*/
private void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean setState) {
- if (mResumedActivity == r) {
- mResumedActivity = null;
- }
- if (mPausingActivity == r) {
- mPausingActivity = null;
- }
+ onActivityRemovedFromStack(r);
r.deferRelaunchUntilPaused = false;
r.frozenBeforeDestroy = false;
@@ -3898,7 +3925,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + r);
r.app = null;
r.removeWindowContainer();
- final TaskRecord task = r.task;
+ final TaskRecord task = r.getTask();
final boolean lastActivity = task != null ? task.removeActivity(r) : false;
// If we are removing the last activity in the task, not including task overlay activities,
// then fall through into the block below to remove the entire task itself
@@ -4044,7 +4071,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
+ ", app=" + (r.app != null ? r.app.processName : "(null)"));
EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
r.userId, System.identityHashCode(r),
- r.task.taskId, r.shortComponentName, reason);
+ r.getTask().taskId, r.shortComponentName, reason);
boolean removedFromHistory = false;
@@ -4276,7 +4303,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
r.userId, System.identityHashCode(r),
- r.task.taskId, r.shortComponentName,
+ r.getTask().taskId, r.shortComponentName,
"proc died without state saved");
if (r.state == ActivityState.RESUMED) {
mService.updateUsageStats(r, false);
@@ -4530,7 +4557,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
}
- final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
+ final TaskRecord task = mResumedActivity != null ? mResumedActivity.getTask() : null;
if (prevIsHome || (task == tr && canGoHome) || (numTasks <= 1 && isOnHomeDisplay())) {
if (!mService.mBooting && !mService.mBooted) {
// Not ready yet!
@@ -4571,7 +4598,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
return;
}
- final TaskRecord startTask = start.task;
+ final TaskRecord startTask = start.getTask();
boolean behindFullscreen = false;
boolean updatedConfig = false;
@@ -4579,7 +4606,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final TaskRecord task = mTaskHistory.get(taskIndex);
final ArrayList<ActivityRecord> activities = task.mActivities;
int activityIndex =
- (start.task == task) ? activities.indexOf(start) : activities.size() - 1;
+ (start.getTask() == task) ? activities.indexOf(start) : activities.size() - 1;
for (; activityIndex >= 0; --activityIndex) {
final ActivityRecord r = activities.get(activityIndex);
updatedConfig |= r.ensureActivityConfigurationLocked(0 /* globalChanges */,
@@ -4740,7 +4767,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|| filterByClasses.contains(r.realActivity.getClassName())))
|| (packageName == null && r.userId == userId);
if ((userId == UserHandle.USER_ALL || r.userId == userId)
- && (sameComponent || r.task == lastTask)
+ && (sameComponent || r.getTask() == lastTask)
&& (r.app == null || evenPersistent || !r.app.persistent)) {
if (!doit) {
if (r.finishing) {
@@ -4766,7 +4793,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
r.app = null;
}
- lastTask = r.task;
+ lastTask = r.getTask();
if (finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop",
true)) {
// r has been deleted from mActivities, accommodate.
@@ -4817,7 +4844,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (DEBUG_ALL) Slog.v(
TAG, r.intent.getComponent().flattenToShortString()
- + ": task=" + r.task);
+ + ": task=" + r.getTask());
}
RunningTaskInfo ci = new RunningTaskInfo();
@@ -4833,8 +4860,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
topTask = false;
}
- if (top.task != null) {
- ci.description = top.task.lastDescription;
+ if (top.getTask() != null) {
+ ci.description = top.getTask().lastDescription;
}
ci.numActivities = numActivities;
ci.numRunning = numRunning;
@@ -4983,9 +5010,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
task.removeWindowContainer();
}
- final ActivityRecord r = mResumedActivity;
- if (r != null && r.task == task) {
- mResumedActivity = null;
+ for (ActivityRecord record : task.mActivities) {
+ onActivityRemovedFromStack(record);
}
final int taskNdx = mTaskHistory.indexOf(task);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f16849ddc672..b72cd73e85cf 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -164,6 +164,7 @@ import android.view.Display;
import android.view.InputEvent;
import android.view.Surface;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.ReferrerIntent;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -173,6 +174,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.wm.StackWindowController;
import com.android.server.wm.WindowManagerService;
import java.io.FileDescriptor;
@@ -553,9 +555,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
}
- public ActivityStackSupervisor(ActivityManagerService service) {
+ public ActivityStackSupervisor(ActivityManagerService service, Looper looper) {
mService = service;
- mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
+ mHandler = new ActivityStackSupervisorHandler(looper);
mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext);
mKeyguardController = new KeyguardController(service, this);
}
@@ -722,7 +724,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
if (prev != null) {
- prev.task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
+ prev.getTask().setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
}
mHomeStack.moveHomeStackTaskToTop();
@@ -1314,7 +1316,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mService.updateLruProcessLocked(app, true, null);
mService.updateOomAdjLocked();
- final TaskRecord task = r.task;
+ final TaskRecord task = r.getTask();
if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE ||
task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV) {
setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false);
@@ -2622,7 +2624,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
for (int k = 0; k < proc.activities.size(); k++) {
- TaskRecord otherTask = proc.activities.get(k).task;
+ TaskRecord otherTask = proc.activities.get(k).getTask();
if (tr.taskId != otherTask.taskId && otherTask.inRecents) {
// Don't kill process(es) that has an activity in a different task that is
// also in recents.
@@ -2837,7 +2839,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final PinnedActivityStack stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
try {
- final TaskRecord task = r.task;
+ final TaskRecord task = r.getTask();
if (r == task.getStack().getVisibleBehindActivity()) {
// An activity can't be pinned and visible behind at the same time. Go ahead and
@@ -2910,7 +2912,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return false;
}
- final TaskRecord task = r.task;
+ final TaskRecord task = r.getTask();
final ActivityStack stack = r.getStack();
if (stack == null) {
Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: r="
@@ -3203,7 +3205,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Called when WindowManager has finished animating the launchingBehind activity to the back.
private void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
- final TaskRecord task = r.task;
+ final TaskRecord task = r.getTask();
final ActivityStack stack = task.getStack();
r.mLaunchTaskBehind = false;
@@ -3216,7 +3218,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// task has been shown briefly
final ActivityRecord top = stack.topActivity();
if (top != null) {
- top.task.touchActiveTime();
+ top.getTask().touchActiveTime();
}
}
@@ -3315,17 +3317,19 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
continue;
}
- if (r.task != null) {
- if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + r.task
+
+ final TaskRecord task = r.getTask();
+ if (task != null) {
+ if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + task
+ " from " + r);
if (firstTask == null) {
- firstTask = r.task;
- } else if (firstTask != r.task) {
+ firstTask = task;
+ } else if (firstTask != task) {
if (tasks == null) {
tasks = new ArraySet<>();
tasks.add(firstTask);
}
- tasks.add(r.task);
+ tasks.add(task);
}
}
}
@@ -3664,8 +3668,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
pw.println(header2);
header2 = null;
}
- if (lastTask != r.task) {
- lastTask = r.task;
+ if (lastTask != r.getTask()) {
+ lastTask = r.getTask();
pw.print(prefix);
pw.print(full ? "* " : " ");
pw.println(lastTask);
@@ -4080,7 +4084,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
}
final ActivityRecord r = topRunningActivityLocked();
- final TaskRecord task = r != null ? r.task : null;
+ final TaskRecord task = r != null ? r.getTask() : null;
if (mLockTaskModeTasks.isEmpty() && task != null
&& task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
// This task must have just been authorized.
@@ -4390,19 +4394,24 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
synchronized (mService) {
mStackId = stackId;
mActivityDisplay = activityDisplay;
- switch (mStackId) {
- case PINNED_STACK_ID:
- new PinnedActivityStack(this, mRecentTasks, onTop);
- break;
- default:
- new ActivityStack(this, mRecentTasks, onTop);
- break;
- }
mIdString = "ActivtyContainer{" + mStackId + "}";
+
+ createStack(stackId, onTop);
if (DEBUG_STACK) Slog.d(TAG_STACK, "Creating " + this);
}
}
+ protected void createStack(int stackId, boolean onTop) {
+ switch (stackId) {
+ case PINNED_STACK_ID:
+ new PinnedActivityStack(this, mRecentTasks, onTop);
+ break;
+ default:
+ new ActivityStack(this, mRecentTasks, onTop);
+ break;
+ }
+ }
+
/**
* Adds the stack to specified display. Also calls WindowManager to do the same from
* {@link ActivityStack#reparent(ActivityDisplay, boolean)}.
@@ -4926,7 +4935,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mService.mActivityStarter.postStartActivityProcessing(task.getTopActivity(),
ActivityManager.START_TASK_TO_FRONT,
- sourceRecord != null ? sourceRecord.task.getStackId() : INVALID_STACK_ID,
+ sourceRecord != null ? sourceRecord.getTask().getStackId() : INVALID_STACK_ID,
sourceRecord, task.getStack());
return ActivityManager.START_TASK_TO_FRONT;
}
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 547161ac4169..cafc4f0ecc96 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -188,10 +188,10 @@ class ActivityStartInterceptor {
}
ActivityRecord homeActivityRecord = mSupervisor.getHomeActivity();
- if (homeActivityRecord != null && homeActivityRecord.task != null) {
+ if (homeActivityRecord != null && homeActivityRecord.getTask() != null) {
// Showing credential confirmation activity in home task to avoid stopping multi-windowed
// mode after showing the full-screen credential confirmation activity.
- mActivityOptions.setLaunchTaskId(homeActivityRecord.task.taskId);
+ mActivityOptions.setLaunchTaskId(homeActivityRecord.getTask().taskId);
}
final UserInfo parent = mUserManager.getProfileParent(mUserId);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 18e74080490d..b4085697f2da 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -79,7 +79,6 @@ import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
-import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS;
@@ -87,8 +86,6 @@ import static com.android.server.am.EventLogTags.AM_NEW_INTENT;
import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
-import static java.lang.Integer.MAX_VALUE;
-
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -335,7 +332,7 @@ class ActivityStarter {
}
if (err == ActivityManager.START_SUCCESS && sourceRecord != null
- && sourceRecord.task.voiceSession != null) {
+ && sourceRecord.getTask().voiceSession != null) {
// If this activity is being launched as part of a voice session, we need
// 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
@@ -575,7 +572,7 @@ class ActivityStarter {
// visibility instead of using this flag.
final boolean noDisplayActivityOverHome = sourceRecord != null
&& sourceRecord.noDisplay
- && sourceRecord.task.getTaskToReturnTo() == HOME_ACTIVITY_TYPE;
+ && sourceRecord.getTask().getTaskToReturnTo() == HOME_ACTIVITY_TYPE;
if (startedActivityStackId == DOCKED_STACK_ID
&& (prevFocusedStackId == HOME_STACK_ID || noDisplayActivityOverHome)) {
final ActivityStack homeStack = mSupervisor.getStack(HOME_STACK_ID);
@@ -625,7 +622,7 @@ class ActivityStarter {
FLAG_ACTIVITY_TASK_ON_HOME);
ActivityOptions options = (optionsBundle != null ? new ActivityOptions(optionsBundle)
: ActivityOptions.makeBasic());
- options.setLaunchTaskId(mSupervisor.getHomeActivity().task.taskId);
+ options.setLaunchTaskId(mSupervisor.getHomeActivity().getTask().taskId);
mService.mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
}
@@ -763,7 +760,7 @@ class ActivityStarter {
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
hist.packageName);
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
- hist.task.taskId);
+ hist.getTask().taskId);
}
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
aInfo.packageName);
@@ -967,8 +964,8 @@ class ActivityStarter {
// If we are not able to proceed, disassociate the activity from the task. Leaving an
// activity in an incomplete state can lead to issues, such as performing operations
// without a window container.
- if (result != START_SUCCESS && mStartActivity.task != null) {
- mStartActivity.task.removeActivity(mStartActivity);
+ if (result != START_SUCCESS && mStartActivity.getTask() != null) {
+ mStartActivity.getTask().removeActivity(mStartActivity);
}
mService.mWindowManager.continueSurfaceLayout();
}
@@ -1002,7 +999,7 @@ class ActivityStarter {
// When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
// still needs to be a lock task mode violation since the task gets cleared out and
// the device would otherwise leave the locked task.
- if (mSupervisor.isLockTaskModeViolation(mReusedActivity.task,
+ if (mSupervisor.isLockTaskModeViolation(mReusedActivity.getTask(),
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
mSupervisor.showLockTaskToast();
@@ -1010,13 +1007,13 @@ class ActivityStarter {
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
- if (mStartActivity.task == null) {
- mStartActivity.task = mReusedActivity.task;
+ if (mStartActivity.getTask() == null) {
+ mStartActivity.setTask(mReusedActivity.getTask());
}
- if (mReusedActivity.task.intent == null) {
+ if (mReusedActivity.getTask().intent == null) {
// This task was started because of movement of the activity based on affinity...
// Now that we are actually launching it, we can assign the base intent.
- mReusedActivity.task.setIntent(mStartActivity);
+ mReusedActivity.getTask().setIntent(mStartActivity);
}
// This code path leads to delivering a new intent, we want to make sure we schedule it
@@ -1025,7 +1022,7 @@ class ActivityStarter {
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| isDocumentLaunchesIntoExisting(mLaunchFlags)
|| mLaunchSingleInstance || mLaunchSingleTask) {
- final TaskRecord task = mReusedActivity.task;
+ final TaskRecord task = mReusedActivity.getTask();
// 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
@@ -1037,17 +1034,17 @@ class ActivityStarter {
// the {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The
// task reference is needed in the call below to
// {@link setTargetStackAndMoveToFrontIfNeeded}.
- if (mReusedActivity.task == null) {
- mReusedActivity.task = task;
+ if (mReusedActivity.getTask() == null) {
+ mReusedActivity.setTask(task);
}
if (top != null) {
if (top.frontOfTask) {
// Activity aliases may mean we use different intents for the top activity,
// so make sure the task now has the identity of the new intent.
- top.task.setIntent(mStartActivity);
+ top.getTask().setIntent(mStartActivity);
}
- ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
+ ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.getTask());
top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
}
@@ -1098,7 +1095,7 @@ class ActivityStarter {
&& ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| mLaunchSingleTop || mLaunchSingleTask);
if (dontStart) {
- ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
+ ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.getTask());
// For paranoia, make sure we have correctly resumed the top activity.
topStack.mLastPausedActivity = null;
if (mDoResume) {
@@ -1116,14 +1113,14 @@ class ActivityStarter {
// Don't use mStartActivity.task to show the toast. We're not starting a new activity
// but reusing 'top'. Fields in mStartActivity may not be fully initialized.
mSupervisor.handleNonResizableTaskIfNeeded(
- top.task, preferredLaunchStackId, topStack.mStackId);
+ top.getTask(), preferredLaunchStackId, topStack.mStackId);
return START_DELIVERED_TO_TOP;
}
boolean newTask = false;
final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
- ? mSourceRecord.task : null;
+ ? mSourceRecord.getTask() : null;
// Should this be considered a new task?
int result = START_SUCCESS;
@@ -1150,14 +1147,15 @@ class ActivityStarter {
mService.grantEphemeralAccessLocked(mStartActivity.userId, mIntent,
mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid));
if (mSourceRecord != null) {
- mStartActivity.task.setTaskToReturnTo(mSourceRecord);
+ mStartActivity.getTask().setTaskToReturnTo(mSourceRecord);
}
if (newTask) {
EventLog.writeEvent(
- EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId);
+ EventLogTags.AM_CREATE_TASK, mStartActivity.userId,
+ mStartActivity.getTask().taskId);
}
ActivityStack.logStartActivity(
- EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
+ EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTask());
mTargetStack.mLastPausedActivity = null;
sendPowerHintForLaunchStartIfNeeded(false /* forceSend */);
@@ -1165,7 +1163,8 @@ class ActivityStarter {
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
if (mDoResume) {
- final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
+ final ActivityRecord topTaskActivity =
+ mStartActivity.getTask().topRunningActivityLocked();
if (!mTargetStack.isFocusable()
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& mStartActivity != topTaskActivity)) {
@@ -1197,7 +1196,7 @@ class ActivityStarter {
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
mSupervisor.handleNonResizableTaskIfNeeded(
- mStartActivity.task, preferredLaunchStackId, mTargetStack.mStackId);
+ mStartActivity.getTask(), preferredLaunchStackId, mTargetStack.mStackId);
return START_SUCCESS;
}
@@ -1424,7 +1423,7 @@ class ActivityStarter {
+ "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
mNewTaskInfo = mSourceRecord.info;
- mNewTaskIntent = mSourceRecord.task.intent;
+ mNewTaskIntent = mSourceRecord.getTask().intent;
}
mSourceRecord = null;
mSourceStack = null;
@@ -1516,15 +1515,16 @@ class ActivityStarter {
ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
- if (curTop != null
- && (curTop.task != intentActivity.task || curTop.task != focusStack.topTask())
+ final TaskRecord topTask = curTop != null ? curTop.getTask() : null;
+ if (topTask != null
+ && (topTask != intentActivity.getTask() || topTask != focusStack.topTask())
&& !mAvoidMoveToFront) {
mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
if (mSourceRecord == null || (mSourceStack.topActivity() != null &&
- mSourceStack.topActivity().task == mSourceRecord.task)) {
+ mSourceStack.topActivity().getTask() == mSourceRecord.getTask())) {
// We really do want to push this one into the user's face, right now.
if (mLaunchTaskBehind && mSourceRecord != null) {
- intentActivity.setTaskToAffiliateWith(mSourceRecord.task);
+ intentActivity.setTaskToAffiliateWith(mSourceRecord.getTask());
}
mMovedOtherTask = true;
@@ -1539,13 +1539,13 @@ class ActivityStarter {
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
if (!willClearTask) {
final ActivityStack launchStack = getLaunchStack(
- mStartActivity, mLaunchFlags, mStartActivity.task, mOptions);
+ mStartActivity, mLaunchFlags, mStartActivity.getTask(), mOptions);
+ final TaskRecord intentTask = intentActivity.getTask();
if (launchStack == null || launchStack == mTargetStack) {
// We only want to move to the front, if we aren't going to launch on a
// different stack. If we launch on a different stack, we will put the
// task on top there.
- mTargetStack.moveTaskToFrontLocked(
- intentActivity.task, mNoAnimation, mOptions,
+ mTargetStack.moveTaskToFrontLocked(intentTask, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
mMovedToFront = true;
} else if (launchStack.mStackId == DOCKED_STACK_ID
@@ -1553,7 +1553,7 @@ class ActivityStarter {
if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
// If we want to launch adjacent and mTargetStack is not the computed
// launch stack - move task to top of computed stack.
- intentActivity.task.reparent(launchStack.mStackId, ON_TOP,
+ intentTask.reparent(launchStack.mStackId, ON_TOP,
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"launchToSide");
} else {
@@ -1561,8 +1561,8 @@ class ActivityStarter {
// We choose to move task to front instead of launching it adjacent
// when specific stack was requested explicitly and it appeared to be
// adjacent stack, but FLAG_ACTIVITY_LAUNCH_ADJACENT was not set.
- mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation,
- mOptions, mStartActivity.appTimeTracker,
+ mTargetStack.moveTaskToFrontLocked(intentTask,
+ mNoAnimation, mOptions, mStartActivity.appTimeTracker,
"bringToFrontInsteadOfAdjacentLaunch");
}
mMovedToFront = true;
@@ -1570,7 +1570,7 @@ class ActivityStarter {
// Target and computed stacks are on different displays and we've
// found a matching task - move the existing instance to that display and
// move it to front.
- intentActivity.task.reparent(launchStack.mStackId, ON_TOP,
+ intentActivity.getTask().reparent(launchStack.mStackId, ON_TOP,
REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
"reparentToDisplay");
mMovedToFront = true;
@@ -1582,7 +1582,7 @@ class ActivityStarter {
intentActivity.showStartingWindow(null /* prev */, false /* newTask */,
true /* taskSwitch */);
}
- updateTaskReturnToType(intentActivity.task, mLaunchFlags, focusStack);
+ updateTaskReturnToType(intentActivity.getTask(), mLaunchFlags, focusStack);
}
}
if (!mMovedToFront && mDoResume) {
@@ -1591,7 +1591,7 @@ class ActivityStarter {
mTargetStack.moveToFront("intentActivityFound");
}
- mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.task, INVALID_STACK_ID,
+ mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(), INVALID_STACK_ID,
mTargetStack.mStackId);
// If the caller has requested that the target task be reset, then do so.
@@ -1635,7 +1635,7 @@ class ActivityStarter {
// launching another activity.
// TODO(b/36119896): We shouldn't trigger activity launches in this path since we are
// already launching one.
- final TaskRecord task = intentActivity.task;
+ final TaskRecord task = intentActivity.getTask();
task.performClearTaskLocked();
mReuseTask = task;
mReuseTask.setIntent(mStartActivity);
@@ -1646,7 +1646,7 @@ class ActivityStarter {
mMovedOtherTask = true;
} else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| mLaunchSingleInstance || mLaunchSingleTask) {
- ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity,
+ ActivityRecord top = intentActivity.getTask().performClearTaskLocked(mStartActivity,
mLaunchFlags);
if (top == null) {
// A special case: we need to start the activity because it is not currently
@@ -1655,11 +1655,11 @@ class ActivityStarter {
mAddingToTask = true;
// We are no longer placing the activity in the task we previously thought we were.
- mStartActivity.task = null;
+ mStartActivity.setTask(null);
// Now pretend like this activity is being started by the top of its task, so it
// is put in the right place.
mSourceRecord = intentActivity;
- final TaskRecord task = mSourceRecord.task;
+ final TaskRecord task = mSourceRecord.getTask();
if (task != null && task.getStack() == null) {
// Target stack got cleared when we all activities were removed above.
// Go ahead and reset it.
@@ -1669,7 +1669,7 @@ class ActivityStarter {
!mLaunchTaskBehind /* toTop */, "startActivityUnchecked");
}
}
- } else if (mStartActivity.realActivity.equals(intentActivity.task.realActivity)) {
+ } else if (mStartActivity.realActivity.equals(intentActivity.getTask().realActivity)) {
// In this case the top activity on the task is the same as the one being launched,
// so we take that as a request to bring the task to the foreground. If the top
// activity in the task is the root activity, deliver this new intent to it if it
@@ -1677,13 +1677,13 @@ class ActivityStarter {
if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
&& intentActivity.realActivity.equals(mStartActivity.realActivity)) {
ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity,
- intentActivity.task);
+ intentActivity.getTask());
if (intentActivity.frontOfTask) {
- intentActivity.task.setIntent(mStartActivity);
+ intentActivity.getTask().setIntent(mStartActivity);
}
intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
- } else if (!intentActivity.task.isSameIntentFilter(mStartActivity)) {
+ } else if (!intentActivity.getTask().isSameIntentFilter(mStartActivity)) {
// In this case we are launching the root activity of the task, but with a
// different intent. We should start a new instance on top.
mAddingToTask = true;
@@ -1696,13 +1696,13 @@ class ActivityStarter {
// current task.
mAddingToTask = true;
mSourceRecord = intentActivity;
- } else if (!intentActivity.task.rootWasReset) {
+ } else if (!intentActivity.getTask().rootWasReset) {
// In this case we are launching into an existing task that has not yet been started
// from its front door. The current task has been brought to the front. Ideally,
// we'd probably like to place this new task at the bottom of its stack, but that's
// a little hard to do with the current organization of the code so for now we'll
// just drop it.
- intentActivity.task.setIntent(mStartActivity);
+ intentActivity.getTask().setIntent(mStartActivity);
}
}
@@ -1736,11 +1736,11 @@ class ActivityStarter {
mService.resizeStack(
stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
} else {
- mStartActivity.task.updateOverrideConfiguration(mLaunchBounds);
+ mStartActivity.getTask().updateOverrideConfiguration(mLaunchBounds);
}
}
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
- + " in new task " + mStartActivity.task);
+ + " in new task " + mStartActivity.getTask());
} else {
addOrReparentStartingActivity(mReuseTask, "setTaskFromReuseOrCreateNewTask");
}
@@ -1749,7 +1749,7 @@ class ActivityStarter {
mStartActivity.setTaskToAffiliateWith(taskToAffiliate);
}
- if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
+ if (mSupervisor.isLockTaskModeViolation(mStartActivity.getTask())) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
@@ -1758,7 +1758,7 @@ class ActivityStarter {
// If stack id is specified in activity options, usually it means that activity is
// launched not from currently focused stack (e.g. from SysUI or from shell) - in
// that case we check the target stack.
- updateTaskReturnToType(mStartActivity.task, mLaunchFlags,
+ updateTaskReturnToType(mStartActivity.getTask(), mLaunchFlags,
preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack);
}
if (mDoResume) {
@@ -1768,19 +1768,19 @@ class ActivityStarter {
}
private int setTaskFromSourceRecord() {
- if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
+ if (mSupervisor.isLockTaskModeViolation(mSourceRecord.getTask())) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
- final TaskRecord sourceTask = mSourceRecord.task;
+ final TaskRecord sourceTask = mSourceRecord.getTask();
final ActivityStack sourceStack = mSourceRecord.getStack();
// We only want to allow changing stack if the target task is not the top one,
// otherwise we would move the launching task to the other side, rather than show
// two side by side.
final boolean moveStackAllowed = sourceStack.topTask() != sourceTask;
if (moveStackAllowed) {
- mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
+ mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.getTask(),
mOptions);
}
@@ -1805,7 +1805,7 @@ class ActivityStarter {
ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, mLaunchFlags);
mKeepCurTransition = true;
if (top != null) {
- ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
+ ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.getTask());
top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
// For paranoia, make sure we have correctly resumed the top activity.
mTargetStack.mLastPausedActivity = null;
@@ -1821,7 +1821,7 @@ class ActivityStarter {
// stack if so.
final ActivityRecord top = sourceTask.findActivityInHistoryLocked(mStartActivity);
if (top != null) {
- final TaskRecord task = top.task;
+ final TaskRecord task = top.getTask();
task.moveActivityToFrontLocked(top);
top.updateOptionsLocked(mOptions);
ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, task);
@@ -1838,7 +1838,7 @@ class ActivityStarter {
// the same task as the one that is starting it.
addOrReparentStartingActivity(sourceTask, "setTaskFromSourceRecord");
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
- + " in existing task " + mStartActivity.task + " from source " + mSourceRecord);
+ + " in existing task " + mStartActivity.getTask() + " from source " + mSourceRecord);
return START_SUCCESS;
}
@@ -1861,7 +1861,7 @@ class ActivityStarter {
|| mLaunchSingleTop || mLaunchSingleTask) {
mTargetStack.moveTaskToFrontLocked(mInTask, mNoAnimation, mOptions,
mStartActivity.appTimeTracker, "inTaskToFront");
- ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
+ ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.getTask());
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and the client said not to do
// anything if that is the case, so this is it!
@@ -1901,7 +1901,7 @@ class ActivityStarter {
addOrReparentStartingActivity(mInTask, "setTaskFromInTask");
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
- + " in explicit task " + mStartActivity.task);
+ + " in explicit task " + mStartActivity.getTask());
return START_SUCCESS;
}
@@ -1913,17 +1913,17 @@ class ActivityStarter {
mTargetStack.moveToFront("addingToTopTask");
}
final ActivityRecord prev = mTargetStack.topActivity();
- final TaskRecord task = (prev != null) ? prev.task : mTargetStack.createTaskRecord(
+ final TaskRecord task = (prev != null) ? prev.getTask() : mTargetStack.createTaskRecord(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId), mStartActivity.info,
mIntent, null, null, true, mStartActivity.mActivityType);
addOrReparentStartingActivity(task, "setTaskToCurrentTopOrCreateNewTask");
mTargetStack.positionChildWindowContainerAtTop(task);
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
- + " in new guessed " + mStartActivity.task);
+ + " in new guessed " + mStartActivity.getTask());
}
private void addOrReparentStartingActivity(TaskRecord parent, String reason) {
- if (mStartActivity.task == null || mStartActivity.task == parent) {
+ if (mStartActivity.getTask() == null || mStartActivity.getTask() == parent) {
parent.addActivityToTop(mStartActivity);
} else {
mStartActivity.reparent(parent, parent.mActivities.size() /* top */, reason);
@@ -1973,7 +1973,7 @@ class ActivityStarter {
private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds,
int launchFlags, ActivityOptions aOptions) {
- final TaskRecord task = r.task;
+ final TaskRecord task = r.getTask();
ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions);
if (stack != null) {
return stack;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 27a2461a8827..0c2c2043fb15 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -660,17 +660,6 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
// we are coming from in WM before we reparent because it became empty.
mWindowContainerController.reparent(toStack.getWindowContainerController(), position);
- // Reset the resumed activity on the previous stack
- if (wasResumed) {
- sourceStack.mResumedActivity = null;
- }
-
- // Reset the paused activity on the previous stack
- if (wasPaused) {
- sourceStack.mPausingActivity = null;
- sourceStack.removeTimeoutsForActivityLocked(r);
- }
-
// Move the task
sourceStack.removeTask(this, reason, REMOVE_TASK_MODE_MOVING);
toStack.addTask(this, position, false /* schedulePictureInPictureModeChange */, reason);
@@ -1212,14 +1201,13 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
* be in the current task or unparented to any task.
*/
void addActivityAtIndex(int index, ActivityRecord r) {
- if (r.task != null && r.task != this) {
+ TaskRecord task = r.getTask();
+ if (task != null && task != this) {
throw new IllegalArgumentException("Can not add r=" + " to task=" + this
- + " current parent=" + r.task);
+ + " current parent=" + task);
}
- // TODO(b/36505427): Maybe make task private to ActivityRecord so we can also do
- // onParentChanged() within the setter?
- r.task = this;
- r.onParentChanged();
+
+ r.setTask(this);
// Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
if (!mActivities.remove(r) && r.fullscreen) {
@@ -1274,15 +1262,21 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
}
/**
- * @return true if this was the last activity in the task
+ * Removes the specified activity from this task.
+ * @param r The {@link ActivityRecord} to remove.
+ * @return true if this was the last activity in the task.
*/
boolean removeActivity(ActivityRecord r) {
- if (r.task != this) {
+ return removeActivity(r, false /*reparenting*/);
+ }
+
+ boolean removeActivity(ActivityRecord r, boolean reparenting) {
+ if (r.getTask() != this) {
throw new IllegalArgumentException(
"Activity=" + r + " does not belong to task=" + this);
}
- r.task = null;
+ r.setTask(null /*task*/, reparenting);
if (mActivities.remove(r) && r.fullscreen) {
// Was previously in list.
@@ -1437,7 +1431,7 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
TaskThumbnail getTaskThumbnailLocked() {
if (mStack != null) {
final ActivityRecord resumedActivity = mStack.mResumedActivity;
- if (resumedActivity != null && resumedActivity.task == this) {
+ if (resumedActivity != null && resumedActivity.getTask() == this) {
final Bitmap thumbnail = resumedActivity.screenshotActivityLocked();
setLastThumbnailLocked(thumbnail);
}
@@ -1953,7 +1947,7 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
task.updateOverrideConfiguration(bounds);
for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
- activities.get(activityNdx).task = task;
+ activities.get(activityNdx).setTask(task);
}
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
new file mode 100644
index 000000000000..54ecab3af542
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.ComponentName;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+/**
+ * Tests for the {@link ActivityRecord} class.
+ *
+ * Build/Install/Run:
+ * bit FrameworksServicesTests:com.android.server.am.ActivityRecordTests
+ */
+@MediumTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ActivityRecordTests extends ActivityTestsBase {
+ private final ComponentName testActivityComponent =
+ ComponentName.unflattenFromString("com.foo/.BarActivity");
+ @Test
+ public void testStackCleanupOnClearingTask() throws Exception {
+ final ActivityManagerService service = createActivityManagerService();
+ final TestActivityStack testStack = new ActivityStackBuilder(service).build();
+ final TaskRecord task = createTask(service, testActivityComponent, testStack);
+ final ActivityRecord record = createActivity(service, testActivityComponent, task);
+
+ record.setTask(null);
+ assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1);
+ }
+
+ @Test
+ public void testStackCleanupOnActivityRemoval() throws Exception {
+ final ActivityManagerService service = createActivityManagerService();
+ final TestActivityStack testStack = new ActivityStackBuilder(service).build();
+ final TaskRecord task = createTask(service, testActivityComponent, testStack);
+ final ActivityRecord record = createActivity(service, testActivityComponent, task);
+
+ task.removeActivity(record);
+ assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1);
+ }
+
+ @Test
+ public void testStackCleanupOnTaskRemoval() throws Exception {
+ final ActivityManagerService service = createActivityManagerService();
+ final TestActivityStack testStack = new ActivityStackBuilder(service).build();
+ final TaskRecord task = createTask(service, testActivityComponent, testStack);
+ final ActivityRecord record = createActivity(service, testActivityComponent, task);
+
+ testStack.removeTask(task, null /*reason*/, ActivityStack.REMOVE_TASK_MODE_MOVING);
+ assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 1);
+ }
+
+ @Test
+ public void testNoCleanupMovingActivityInSameStack() throws Exception {
+ final ActivityManagerService service = createActivityManagerService();
+ final TestActivityStack testStack = new ActivityStackBuilder(service).build();
+ final TaskRecord oldTask = createTask(service, testActivityComponent, testStack);
+ final ActivityRecord record = createActivity(service, testActivityComponent, oldTask);
+ final TaskRecord newTask = createTask(service, testActivityComponent, testStack);
+
+ record.reparent(newTask, 0, null /*reason*/);
+ assertTrue(testStack.onActivityRemovedFromStackInvocationCount() == 0);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
new file mode 100644
index 000000000000..c5cc2ff22abd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import static org.mockito.Mockito.mock;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.test.InstrumentationRegistry;
+import com.android.server.AttributeCache;
+import com.android.server.wm.AppWindowContainerController;
+import com.android.server.wm.StackWindowController;
+
+import com.android.server.wm.WindowManagerService;
+import com.android.server.wm.WindowTestUtils;
+import org.junit.Before;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * A base class to handle common operations in activity related unit tests.
+ */
+public class ActivityTestsBase {
+ private final Context mContext = InstrumentationRegistry.getContext();
+ private static boolean sLooperPrepared;
+ private Handler mHandler;
+
+ // Grabbing an instance of {@link WindowManagerService} creates it if not present so this must
+ // be called at before any tests.
+ private final WindowManagerService mWms = WindowTestUtils.getWindowManagerService(mContext);
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ if (!sLooperPrepared) {
+ sLooperPrepared = true;
+ Looper.prepare();
+ }
+ }
+
+ protected ActivityManagerService createActivityManagerService() {
+ return new TestActivityManagerService(mContext);
+ }
+
+ protected static TestActivityStack createActivityStack(ActivityManagerService service,
+ int stackId, int displayId, boolean onTop) {
+ if (service.mStackSupervisor instanceof TestActivityStackSupervisor) {
+ final TestActivityStack stack = ((TestActivityStackSupervisor) service.mStackSupervisor)
+ .createTestStack(stackId, onTop);
+ return stack;
+ }
+
+ return null;
+ }
+
+ protected static ActivityRecord createActivity(ActivityManagerService service,
+ ComponentName component, TaskRecord task) {
+ Intent intent = new Intent();
+ intent.setComponent(component);
+ final ActivityInfo aInfo = new ActivityInfo();
+ aInfo.applicationInfo = new ApplicationInfo();
+ aInfo.applicationInfo.packageName = component.getPackageName();
+ AttributeCache.init(service.mContext);
+ final ActivityRecord activity = new ActivityRecord(service, null /* caller */,
+ 0 /* launchedFromPid */, 0, null, intent, null,
+ aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,
+ 0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */,
+ service.mStackSupervisor, null /* container */, null /* options */,
+ null /* sourceRecord */);
+ activity.mWindowContainerController = mock(AppWindowContainerController.class);
+
+ if (task != null) {
+ task.addActivityToTop(activity);
+ }
+
+ return activity;
+ }
+
+ protected static TaskRecord createTask(ActivityManagerService service,
+ ComponentName component, ActivityStack stack) {
+ final ActivityInfo aInfo = new ActivityInfo();
+ aInfo.applicationInfo = new ApplicationInfo();
+ aInfo.applicationInfo.packageName = component.getPackageName();
+
+ Intent intent = new Intent();
+ intent.setComponent(component);
+
+ final TaskRecord task = new TaskRecord(service, 0, aInfo, intent /*intent*/,
+ null /*_taskDescription*/, null /*thumbnailInfo*/);
+ stack.addTask(task, true, "creating test task");
+ task.setStack(stack);
+ task.createWindowContainer(true, true);
+
+ return task;
+ }
+
+ /**
+ * An {@link ActivityManagerService} subclass which provides a test
+ * {@link ActivityStackSupervisor}.
+ */
+ protected static class TestActivityManagerService extends ActivityManagerService {
+ public TestActivityManagerService(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected ActivityStackSupervisor createStackSupervisor() {
+ return new TestActivityStackSupervisor(this, new Handler().getLooper());
+ }
+ }
+
+ /**
+ * An {@link ActivityStackSupervisor} which stubs out certain methods that depend on
+ * setup not available in the test environment. Also specifies an injector for
+ */
+ protected static class TestActivityStackSupervisor extends ActivityStackSupervisor {
+ public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) {
+ super(service, looper);
+ }
+
+ // Invoked during {@link ActivityStack} creation.
+ @Override
+ void updateUIDsPresentOnDisplay() {
+ }
+
+ public TestActivityStack createTestStack(int stackId, boolean onTop) {
+ final ActivityDisplay display = new ActivityDisplay();
+ final TestActivityContainer container =
+ new TestActivityContainer(stackId, display, onTop);
+ return container.getStack();
+ }
+
+ private class TestActivityContainer extends ActivityContainer {
+ private TestActivityStack mStack;
+ TestActivityContainer(int stackId, ActivityDisplay activityDisplay, boolean onTop) {
+ super(stackId, activityDisplay, onTop);
+ }
+
+ @Override
+ protected void createStack(int stackId, boolean onTop) {
+ mStack = new TestActivityStack(this, null /*recentTasks*/, onTop);
+ }
+
+ public TestActivityStack getStack() {
+ return mStack;
+ }
+ }
+ }
+
+ /**
+ * Override of {@link ActivityStack} that tracks test metrics, such as the number of times a
+ * method is called. Note that its functionality depends on the implementations of the
+ * construction arguments.
+ */
+ protected static class TestActivityStack<T extends StackWindowController>
+ extends ActivityStack<T> {
+ private int mOnActivityRemovedFromStackCount = 0;
+ private T mContainerController;
+ TestActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer,
+ RecentTasks recentTasks, boolean onTop) {
+ super(activityContainer, recentTasks, onTop);
+ }
+
+ @Override
+ void onActivityRemovedFromStack(ActivityRecord r) {
+ mOnActivityRemovedFromStackCount++;
+ super.onActivityRemovedFromStack(r);
+ }
+
+ // Returns the number of times {@link #onActivityRemovedFromStack} has been called
+ public int onActivityRemovedFromStackInvocationCount() {
+ return mOnActivityRemovedFromStackCount;
+ }
+
+ @Override
+ protected T createStackWindowController(int displayId, boolean onTop,
+ Rect outBounds) {
+ mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController();
+ return mContainerController;
+ }
+
+ @Override
+ T getWindowContainerController() {
+ return mContainerController;
+ }
+ }
+
+ protected static class ActivityStackBuilder {
+ private boolean mOnTop = true;
+ private int mStackId = 0;
+ private int mDisplayId = 1;
+
+ private final ActivityManagerService mService;
+
+ public ActivityStackBuilder(ActivityManagerService ams) {
+ mService = ams;
+ }
+
+ public ActivityStackBuilder setOnTop(boolean onTop) {
+ mOnTop = onTop;
+ return this;
+ }
+
+ public ActivityStackBuilder setStackId(int id) {
+ mStackId = id;
+ return this;
+ }
+
+ public ActivityStackBuilder setDisplayId(int id) {
+ mDisplayId = id;
+ return this;
+ }
+
+ public TestActivityStack build() {
+ return createActivityStack(mService, mStackId, mDisplayId, mOnTop);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index 2ccaefc4512e..25004de60676 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -44,7 +44,8 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
@Test
public void testRemoveContainer() throws Exception {
- final TestAppWindowContainerController controller = createAppWindowController();
+ final WindowTestUtils.TestAppWindowContainerController controller =
+ createAppWindowController();
// Assert token was added to display.
assertNotNull(sDisplayContent.getWindowToken(controller.mToken.asBinder()));
@@ -61,7 +62,8 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
@Test
public void testSetOrientation() throws Exception {
- final TestAppWindowContainerController controller = createAppWindowController();
+ final WindowTestUtils.TestAppWindowContainerController controller =
+ createAppWindowController();
// Assert orientation is unspecified to start.
assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation());
@@ -92,7 +94,8 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
@Test
public void testCreateRemoveStartingWindow() throws Exception {
- final TestAppWindowContainerController controller = createAppWindowController();
+ final WindowTestUtils.TestAppWindowContainerController controller =
+ createAppWindowController();
controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false);
waitUntilHandlerIdle();
@@ -105,8 +108,10 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
@Test
public void testTransferStartingWindow() throws Exception {
- final TestAppWindowContainerController controller1 = createAppWindowController();
- final TestAppWindowContainerController controller2 = createAppWindowController();
+ final WindowTestUtils.TestAppWindowContainerController controller1 =
+ createAppWindowController();
+ final WindowTestUtils.TestAppWindowContainerController controller2 =
+ createAppWindowController();
controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false);
waitUntilHandlerIdle();
@@ -120,8 +125,10 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
@Test
public void testTransferStartingWindowWhileCreating() throws Exception {
- final TestAppWindowContainerController controller1 = createAppWindowController();
- final TestAppWindowContainerController controller2 = createAppWindowController();
+ final WindowTestUtils.TestAppWindowContainerController controller1 =
+ createAppWindowController();
+ final WindowTestUtils.TestAppWindowContainerController controller2 =
+ createAppWindowController();
sPolicy.setRunnableWhenAddingSplashScreen(() -> {
// Surprise, ...! Transfer window in the middle of the creation flow.
@@ -140,16 +147,16 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
public void testReparent() throws Exception {
final StackWindowController stackController =
createStackControllerOnDisplay(sDisplayContent);
- final TestTaskWindowContainerController taskController1 =
- new TestTaskWindowContainerController(stackController);
- final TestAppWindowContainerController appWindowController1 = createAppWindowController(
- taskController1);
- final TestTaskWindowContainerController taskController2 =
- new TestTaskWindowContainerController(stackController);
- final TestAppWindowContainerController appWindowController2 = createAppWindowController(
- taskController2);
- final TestTaskWindowContainerController taskController3 =
- new TestTaskWindowContainerController(stackController);
+ final WindowTestUtils.TestTaskWindowContainerController taskController1 =
+ new WindowTestUtils.TestTaskWindowContainerController(stackController);
+ final WindowTestUtils.TestAppWindowContainerController appWindowController1 =
+ createAppWindowController(taskController1);
+ final WindowTestUtils.TestTaskWindowContainerController taskController2 =
+ new WindowTestUtils.TestTaskWindowContainerController(stackController);
+ final WindowTestUtils.TestAppWindowContainerController appWindowController2 =
+ createAppWindowController(taskController2);
+ final WindowTestUtils.TestTaskWindowContainerController taskController3 =
+ new WindowTestUtils.TestTaskWindowContainerController(stackController);
try {
appWindowController1.reparent(taskController1, 0);
@@ -169,16 +176,18 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
// Reparent the app window and ensure that it is moved
appWindowController1.reparent(taskController2, 0);
assertEquals(taskController2.mContainer, appWindowController1.mContainer.getParent());
- assertEquals(0, ((TestAppWindowToken) appWindowController1.mContainer).positionInParent());
- assertEquals(1, ((TestAppWindowToken) appWindowController2.mContainer).positionInParent());
+ assertEquals(0, ((WindowTestUtils.TestAppWindowToken) appWindowController1.mContainer)
+ .positionInParent());
+ assertEquals(1, ((WindowTestUtils.TestAppWindowToken) appWindowController2.mContainer)
+ .positionInParent());
}
- private TestAppWindowContainerController createAppWindowController() {
- return createAppWindowController(new TestTaskWindowContainerController());
+ private WindowTestUtils.TestAppWindowContainerController createAppWindowController() {
+ return createAppWindowController(new WindowTestUtils.TestTaskWindowContainerController());
}
- private TestAppWindowContainerController createAppWindowController(
- TestTaskWindowContainerController taskController) {
- return new TestAppWindowContainerController(taskController);
+ private WindowTestUtils.TestAppWindowContainerController createAppWindowController(
+ WindowTestUtils.TestTaskWindowContainerController taskController) {
+ return new WindowTestUtils.TestAppWindowContainerController(taskController);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 2003b91bcfad..7a7ca3f4000a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -51,7 +51,8 @@ public class AppWindowTokenTests extends WindowTestsBase {
@Test
public void testAddWindow_Order() throws Exception {
- final TestAppWindowToken token = new TestAppWindowToken(sDisplayContent);
+ final WindowTestUtils.TestAppWindowToken token =
+ new WindowTestUtils.TestAppWindowToken(sDisplayContent);
assertEquals(0, token.getWindowsCount());
@@ -78,7 +79,8 @@ public class AppWindowTokenTests extends WindowTestsBase {
@Test
public void testFindMainWindow() throws Exception {
- final TestAppWindowToken token = new TestAppWindowToken(sDisplayContent);
+ final WindowTestUtils.TestAppWindowToken token =
+ new WindowTestUtils.TestAppWindowToken(sDisplayContent);
assertNull(token.findMainWindow());
@@ -102,12 +104,13 @@ public class AppWindowTokenTests extends WindowTestsBase {
// Create an app window with token on a display.
final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
final Task task = createTaskInStack(stack, 0 /* userId */);
- final TestAppWindowToken appWindowToken = new TestAppWindowToken(sDisplayContent);
+ final WindowTestUtils.TestAppWindowToken appWindowToken =
+ new WindowTestUtils.TestAppWindowToken(sDisplayContent);
task.addChild(appWindowToken, 0);
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
TYPE_BASE_APPLICATION);
attrs.setTitle("AppWindow");
- final TestWindowState appWindow = new TestWindowState(attrs, appWindowToken);
+ final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, appWindowToken);
appWindowToken.addWindow(appWindow);
// Set initial orientation and update.
@@ -137,12 +140,13 @@ public class AppWindowTokenTests extends WindowTestsBase {
final DisplayContent defaultDisplayContent = sWm.getDefaultDisplayContentLocked();
final TaskStack stack = createTaskStackOnDisplay(defaultDisplayContent);
final Task task = createTaskInStack(stack, 0 /* userId */);
- final TestAppWindowToken appWindowToken = new TestAppWindowToken(defaultDisplayContent);
+ final WindowTestUtils.TestAppWindowToken appWindowToken =
+ new WindowTestUtils.TestAppWindowToken(defaultDisplayContent);
task.addChild(appWindowToken, 0);
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
TYPE_BASE_APPLICATION);
attrs.setTitle("AppWindow");
- final TestWindowState appWindow = new TestWindowState(attrs, appWindowToken);
+ final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, appWindowToken);
appWindowToken.addWindow(appWindow);
// Set initial orientation and update.
@@ -165,7 +169,8 @@ public class AppWindowTokenTests extends WindowTestsBase {
@Test
public void testGetOrientation() throws Exception {
- final TestAppWindowToken token = new TestAppWindowToken(sDisplayContent);
+ final WindowTestUtils.TestAppWindowToken token =
+ new WindowTestUtils.TestAppWindowToken(sDisplayContent);
token.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
token.setFillsParent(false);
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index e3ccd6eef105..d7d365e72480 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -175,7 +175,7 @@ public class DisplayContentTests extends WindowTestsBase {
assertEquals(dc, stack.getDisplayContent());
final Task task = createTaskInStack(stack, 0 /* userId */);
- final TestAppWindowToken token = new TestAppWindowToken(dc);
+ final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(dc);
task.addChild(token, 0);
assertEquals(dc, task.getDisplayContent());
assertEquals(dc, token.getDisplayContent());
diff --git a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
index b0eba0b99567..13098f64bfac 100644
--- a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
@@ -16,12 +16,7 @@
package com.android.server.wm;
-import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
-
import android.graphics.Rect;
-import android.hardware.display.DisplayManagerGlobal;
-import android.view.Display;
-import android.view.DisplayInfo;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,8 +43,8 @@ public class StackWindowControllerTests extends WindowTestsBase {
public void testRemoveContainer() throws Exception {
final StackWindowController stackController =
createStackControllerOnDisplay(sDisplayContent);
- final TestTaskWindowContainerController taskController =
- new TestTaskWindowContainerController(stackController);
+ final WindowTestUtils.TestTaskWindowContainerController taskController =
+ new WindowTestUtils.TestTaskWindowContainerController(stackController);
final TaskStack stack = stackController.mContainer;
final Task task = taskController.mContainer;
@@ -68,11 +63,11 @@ public class StackWindowControllerTests extends WindowTestsBase {
public void testRemoveContainer_deferRemoval() throws Exception {
final StackWindowController stackController =
createStackControllerOnDisplay(sDisplayContent);
- final TestTaskWindowContainerController taskController =
- new TestTaskWindowContainerController(stackController);
+ final WindowTestUtils.TestTaskWindowContainerController taskController =
+ new WindowTestUtils.TestTaskWindowContainerController(stackController);
final TaskStack stack = stackController.mContainer;
- final TestTask task = (TestTask) taskController.mContainer;
+ final WindowTestUtils.TestTask task = (WindowTestUtils.TestTask) taskController.mContainer;
// Stack removal is deferred if one of its child is animating.
task.setLocalIsAnimating(true);
@@ -96,9 +91,9 @@ public class StackWindowControllerTests extends WindowTestsBase {
final StackWindowController stack1Controller =
createStackControllerOnDisplay(sDisplayContent);
final TaskStack stack1 = stack1Controller.mContainer;
- final TestTaskWindowContainerController taskController =
- new TestTaskWindowContainerController(stack1Controller);
- final TestTask task1 = (TestTask) taskController.mContainer;
+ final WindowTestUtils.TestTaskWindowContainerController taskController =
+ new WindowTestUtils.TestTaskWindowContainerController(stack1Controller);
+ final WindowTestUtils.TestTask task1 = (WindowTestUtils.TestTask) taskController.mContainer;
task1.mOnDisplayChangedCalled = false;
// Create second display and put second stack on it.
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index 462bd68dc420..82ea2313e8d7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -56,7 +56,7 @@ public class TaskStackContainersTests extends WindowTestsBase {
// Stack should contain visible app window to be considered visible.
final Task pinnedTask = createTaskInStack(mPinnedStack, 0 /* userId */);
assertFalse(mPinnedStack.isVisible());
- final TestAppWindowToken pinnedApp = new TestAppWindowToken(sDisplayContent);
+ final WindowTestUtils.TestAppWindowToken pinnedApp = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
pinnedTask.addChild(pinnedApp, 0 /* addPos */);
assertTrue(mPinnedStack.isVisible());
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
index 9dbd8a617eec..267e5f77e709 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
@@ -16,9 +16,6 @@
package com.android.server.wm;
-import android.content.pm.ActivityInfo;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -67,12 +64,14 @@ public class TaskStackTests extends WindowTestsBase {
public void testClosingAppDifferentStackOrientation() throws Exception {
final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
final Task task1 = createTaskInStack(stack, 0 /* userId */);
- TestAppWindowToken appWindowToken1 = new TestAppWindowToken(sDisplayContent);
+ WindowTestUtils.TestAppWindowToken appWindowToken1 =
+ new WindowTestUtils.TestAppWindowToken(sDisplayContent);
task1.addChild(appWindowToken1, 0);
appWindowToken1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
final Task task2 = createTaskInStack(stack, 1 /* userId */);
- TestAppWindowToken appWindowToken2 = new TestAppWindowToken(sDisplayContent);
+ WindowTestUtils.TestAppWindowToken appWindowToken2 =
+ new WindowTestUtils.TestAppWindowToken(sDisplayContent);
task2.addChild(appWindowToken2, 0);
appWindowToken2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
@@ -85,12 +84,14 @@ public class TaskStackTests extends WindowTestsBase {
public void testMoveTaskToBackDifferentStackOrientation() throws Exception {
final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
final Task task1 = createTaskInStack(stack, 0 /* userId */);
- TestAppWindowToken appWindowToken1 = new TestAppWindowToken(sDisplayContent);
+ WindowTestUtils.TestAppWindowToken appWindowToken1 =
+ new WindowTestUtils.TestAppWindowToken(sDisplayContent);
task1.addChild(appWindowToken1, 0);
appWindowToken1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
final Task task2 = createTaskInStack(stack, 1 /* userId */);
- TestAppWindowToken appWindowToken2 = new TestAppWindowToken(sDisplayContent);
+ WindowTestUtils.TestAppWindowToken appWindowToken2 =
+ new WindowTestUtils.TestAppWindowToken(sDisplayContent);
task2.addChild(appWindowToken2, 0);
appWindowToken2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
index f79908e906c7..1819c56735eb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
@@ -16,14 +16,9 @@
package com.android.server.wm;
-import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
-
-import android.hardware.display.DisplayManagerGlobal;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.Display;
-import android.view.DisplayInfo;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,10 +40,10 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase {
@Test
public void testRemoveContainer() throws Exception {
- final TestTaskWindowContainerController taskController =
- new TestTaskWindowContainerController();
- final TestAppWindowContainerController appController =
- new TestAppWindowContainerController(taskController);
+ final WindowTestUtils.TestTaskWindowContainerController taskController =
+ new WindowTestUtils.TestTaskWindowContainerController();
+ final WindowTestUtils.TestAppWindowContainerController appController =
+ new WindowTestUtils.TestAppWindowContainerController(taskController);
taskController.removeContainer();
// Assert that the container was removed.
@@ -58,12 +53,12 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase {
@Test
public void testRemoveContainer_deferRemoval() throws Exception {
- final TestTaskWindowContainerController taskController =
- new TestTaskWindowContainerController();
- final TestAppWindowContainerController appController =
- new TestAppWindowContainerController(taskController);
+ final WindowTestUtils.TestTaskWindowContainerController taskController =
+ new WindowTestUtils.TestTaskWindowContainerController();
+ final WindowTestUtils.TestAppWindowContainerController appController =
+ new WindowTestUtils.TestAppWindowContainerController(taskController);
- final TestTask task = (TestTask) taskController.mContainer;
+ final WindowTestUtils.TestTask task = (WindowTestUtils.TestTask) taskController.mContainer;
final AppWindowToken app = appController.mContainer;
task.mShouldDeferRemoval = true;
@@ -85,12 +80,12 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase {
public void testReparent() throws Exception {
final StackWindowController stackController1 =
createStackControllerOnDisplay(sDisplayContent);
- final TestTaskWindowContainerController taskController =
- new TestTaskWindowContainerController(stackController1);
+ final WindowTestUtils.TestTaskWindowContainerController taskController =
+ new WindowTestUtils.TestTaskWindowContainerController(stackController1);
final StackWindowController stackController2 =
createStackControllerOnDisplay(sDisplayContent);
- final TestTaskWindowContainerController taskController2 =
- new TestTaskWindowContainerController(stackController2);
+ final WindowTestUtils.TestTaskWindowContainerController taskController2 =
+ new WindowTestUtils.TestTaskWindowContainerController(stackController2);
boolean gotException = false;
try {
@@ -114,8 +109,8 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase {
taskController.reparent(stackController2, 0);
assertEquals(stackController2.mContainer, taskController.mContainer.getParent());
- assertEquals(0, ((TestTask) taskController.mContainer).positionInParent());
- assertEquals(1, ((TestTask) taskController2.mContainer).positionInParent());
+ assertEquals(0, ((WindowTestUtils.TestTask) taskController.mContainer).positionInParent());
+ assertEquals(1, ((WindowTestUtils.TestTask) taskController2.mContainer).positionInParent());
}
@Test
@@ -124,9 +119,9 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase {
final StackWindowController stack1Controller =
createStackControllerOnDisplay(sDisplayContent);
final TaskStack stack1 = stack1Controller.mContainer;
- final TestTaskWindowContainerController taskController =
- new TestTaskWindowContainerController(stack1Controller);
- final TestTask task1 = (TestTask) taskController.mContainer;
+ final WindowTestUtils.TestTaskWindowContainerController taskController =
+ new WindowTestUtils.TestTaskWindowContainerController(stack1Controller);
+ final WindowTestUtils.TestTask task1 = (WindowTestUtils.TestTask) taskController.mContainer;
task1.mOnDisplayChangedCalled = false;
assertEquals(sDisplayContent, stack1.getDisplayContent());
@@ -134,9 +129,10 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase {
final DisplayContent dc = createNewDisplay();
final StackWindowController stack2Controller = createStackControllerOnDisplay(dc);
final TaskStack stack2 = stack2Controller.mContainer;
- final TestTaskWindowContainerController taskController2 =
- new TestTaskWindowContainerController(stack2Controller);
- final TestTask task2 = (TestTask) taskController2.mContainer;
+ final WindowTestUtils.TestTaskWindowContainerController taskController2 =
+ new WindowTestUtils.TestTaskWindowContainerController(stack2Controller);
+ final WindowTestUtils.TestTask task2 =
+ (WindowTestUtils.TestTask) taskController2.mContainer;
// Reparent and check state
taskController.reparent(stack2Controller, 0);
diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index cf8af6716d34..0eaf5bc3e940 100644
--- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -46,7 +46,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase {
@Test
public void testFlow() throws Exception {
- final AppWindowToken token = new TestAppWindowToken(sDisplayContent);
+ final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
sWm.mUnknownAppVisibilityController.notifyLaunched(token);
sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token);
sWm.mUnknownAppVisibilityController.notifyRelayouted(token);
@@ -58,8 +58,8 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase {
@Test
public void testMultiple() throws Exception {
- final AppWindowToken token1 = new TestAppWindowToken(sDisplayContent);
- final AppWindowToken token2 = new TestAppWindowToken(sDisplayContent);
+ final AppWindowToken token1 = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
+ final AppWindowToken token2 = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
sWm.mUnknownAppVisibilityController.notifyLaunched(token1);
sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token1);
sWm.mUnknownAppVisibilityController.notifyLaunched(token2);
@@ -74,7 +74,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase {
@Test
public void testClear() throws Exception {
- final AppWindowToken token = new TestAppWindowToken(sDisplayContent);
+ final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
sWm.mUnknownAppVisibilityController.notifyLaunched(token);
sWm.mUnknownAppVisibilityController.clear();;
assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
@@ -82,7 +82,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase {
@Test
public void testAppRemoved() throws Exception {
- final AppWindowToken token = new TestAppWindowToken(sDisplayContent);
+ final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
sWm.mUnknownAppVisibilityController.notifyLaunched(token);
sWm.mUnknownAppVisibilityController.appRemoved(token);
assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index 2e6eac091ba8..a2aa058ac063 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -102,7 +102,7 @@ public class WindowFrameTests extends WindowTestsBase {
// Just any non zero value.
sWm.mSystemDecorLayer = 10000;
- mWindowToken = new TestAppWindowToken(sWm.getDefaultDisplayContentLocked());
+ mWindowToken = new WindowTestUtils.TestAppWindowToken(sWm.getDefaultDisplayContentLocked());
mStubStack = new TaskStack(sWm, 0);
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
new file mode 100644
index 000000000000..3a443575332e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.IBinder;
+import android.view.IApplicationToken;
+import android.view.IWindow;
+import android.view.WindowManager;
+
+import static android.app.AppOpsManager.OP_NONE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.res.Configuration.EMPTY;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static org.mockito.Mockito.mock;
+
+/**
+ * A collection of static functions that can be referenced by other test packages to provide access
+ * to WindowManager related test functionality.
+ */
+public class WindowTestUtils {
+ public static int sNextTaskId = 0;
+
+ /**
+ * Retrieves an instance of {@link WindowManagerService}, creating it if necessary.
+ */
+ public static WindowManagerService getWindowManagerService(Context context) {
+ return TestWindowManagerPolicy.getWindowManagerService(context);
+ }
+
+ /**
+ * Creates a mock instance of {@link StackWindowController}.
+ */
+ public static StackWindowController createMockStackWindowContainerController() {
+ StackWindowController controller = mock(StackWindowController.class);
+ controller.mContainer = mock(TestTaskStack.class);
+ return controller;
+ }
+
+ /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
+ public static Task createTaskInStack(WindowManagerService service, TaskStack stack,
+ int userId) {
+ final Task newTask = new Task(WindowTestUtils.sNextTaskId++, stack, userId, service, null,
+ EMPTY, 0, false,
+ false, new ActivityManager.TaskDescription(), null);
+ stack.addTask(newTask, POSITION_TOP);
+ return newTask;
+ }
+
+ /**
+ * An extension of {@link TestTaskStack}, which overrides package scoped methods that would not
+ * normally be mocked out.
+ */
+ public static class TestTaskStack extends TaskStack {
+ TestTaskStack(WindowManagerService service, int stackId) {
+ super(service, stackId);
+ }
+
+ @Override
+ void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) {
+ // Do nothing.
+ }
+ }
+
+ /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
+ public static class TestAppWindowToken extends AppWindowToken {
+
+ TestAppWindowToken(DisplayContent dc) {
+ super(WindowTestsBase.sWm, null, false, dc, true /* fillsParent */,
+ null /* overrideConfig */, null /* bounds */);
+ }
+
+ TestAppWindowToken(WindowManagerService service, IApplicationToken token,
+ boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
+ boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
+ int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
+ boolean alwaysFocusable, AppWindowContainerController controller,
+ Configuration overrideConfig, Rect bounds) {
+ super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen,
+ showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges,
+ launchTaskBehind, alwaysFocusable, controller, overrideConfig, bounds);
+ }
+
+ int getWindowsCount() {
+ return mChildren.size();
+ }
+
+ boolean hasWindow(WindowState w) {
+ return mChildren.contains(w);
+ }
+
+ WindowState getFirstChild() {
+ return mChildren.getFirst();
+ }
+
+ WindowState getLastChild() {
+ return mChildren.getLast();
+ }
+
+ int positionInParent() {
+ return getParent().mChildren.indexOf(this);
+ }
+ }
+
+ /* Used so we can gain access to some protected members of the {@link WindowToken} class */
+ public static class TestWindowToken extends WindowToken {
+ int adj = 0;
+
+ TestWindowToken(int type, DisplayContent dc) {
+ this(type, dc, false /* persistOnEmpty */);
+ }
+
+ TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) {
+ super(WindowTestsBase.sWm, mock(IBinder.class), type, persistOnEmpty, dc,
+ false /* ownerCanManageAppTokens */);
+ }
+
+ int getWindowsCount() {
+ return mChildren.size();
+ }
+
+ boolean hasWindow(WindowState w) {
+ return mChildren.contains(w);
+ }
+
+ @Override
+ int getAnimLayerAdjustment() {
+ return adj;
+ }
+ }
+
+ /* Used so we can gain access to some protected members of the {@link Task} class */
+ public static class TestTask extends Task {
+ boolean mShouldDeferRemoval = false;
+ boolean mOnDisplayChangedCalled = false;
+ private boolean mUseLocalIsAnimating = false;
+ private boolean mIsAnimating = false;
+
+ TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
+ Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
+ boolean homeTask, TaskWindowContainerController controller) {
+ super(taskId, stack, userId, service, bounds, overrideConfig, resizeMode,
+ supportsPictureInPicture, homeTask, new ActivityManager.TaskDescription(),
+ controller);
+ }
+
+ boolean shouldDeferRemoval() {
+ return mShouldDeferRemoval;
+ }
+
+ int positionInParent() {
+ return getParent().mChildren.indexOf(this);
+ }
+
+ @Override
+ void onDisplayChanged(DisplayContent dc) {
+ super.onDisplayChanged(dc);
+ mOnDisplayChangedCalled = true;
+ }
+
+ @Override
+ boolean isAnimating() {
+ return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating();
+ }
+
+ void setLocalIsAnimating(boolean isAnimating) {
+ mUseLocalIsAnimating = true;
+ mIsAnimating = isAnimating;
+ }
+ }
+
+ /**
+ * Used so we can gain access to some protected members of {@link TaskWindowContainerController}
+ * class.
+ */
+ public static class TestTaskWindowContainerController extends TaskWindowContainerController {
+
+ TestTaskWindowContainerController() {
+ this(WindowTestsBase.createStackControllerOnDisplay(WindowTestsBase.sDisplayContent));
+ }
+
+ TestTaskWindowContainerController(StackWindowController stackController) {
+ super(sNextTaskId++, new TaskWindowContainerListener() {
+ @Override
+ public void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
+
+ }
+
+ @Override
+ public void requestResize(Rect bounds, int resizeMode) {
+
+ }
+ }, stackController, 0 /* userId */, null /* bounds */,
+ EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE,
+ false /* supportsPictureInPicture */, false /* homeTask*/, true /* toTop*/,
+ true /* showForAllUsers */, new ActivityManager.TaskDescription(), WindowTestsBase.sWm);
+ }
+
+ @Override
+ TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds,
+ Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
+ boolean homeTask, ActivityManager.TaskDescription taskDescription) {
+ return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode,
+ supportsPictureInPicture, homeTask, this);
+ }
+ }
+
+ public static class TestAppWindowContainerController extends AppWindowContainerController {
+
+ final IApplicationToken mToken;
+
+ TestAppWindowContainerController(TestTaskWindowContainerController taskController) {
+ this(taskController, new TestIApplicationToken());
+ }
+
+ TestAppWindowContainerController(TestTaskWindowContainerController taskController,
+ IApplicationToken token) {
+ super(taskController, token, null /* listener */, 0 /* index */,
+ SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */,
+ true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */,
+ false /* launchTaskBehind */, false /* alwaysFocusable */,
+ 0 /* targetSdkVersion */, 0 /* rotationAnimationHint */,
+ 0 /* inputDispatchingTimeoutNanos */, WindowTestsBase.sWm, null /* overrideConfig */,
+ null /* bounds */);
+ mToken = token;
+ }
+
+ @Override
+ AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
+ boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
+ boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
+ int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
+ boolean alwaysFocusable, AppWindowContainerController controller,
+ Configuration overrideConfig, Rect bounds) {
+ return new TestAppWindowToken(service, token, voiceInteraction, dc,
+ inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
+ orientation,
+ rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
+ controller, overrideConfig, bounds);
+ }
+
+ AppWindowToken getAppWindowToken() {
+ return (AppWindowToken) WindowTestsBase.sDisplayContent.getWindowToken(mToken.asBinder());
+ }
+ }
+
+ public static class TestIApplicationToken implements IApplicationToken {
+
+ private final Binder mBinder = new Binder();
+ @Override
+ public IBinder asBinder() {
+ return mBinder;
+ }
+ }
+
+ /** Used to track resize reports. */
+ public static class TestWindowState extends WindowState {
+ boolean resizeReported;
+
+ TestWindowState(WindowManagerService service, Session session, IWindow window,
+ WindowManager.LayoutParams attrs, WindowToken token) {
+ super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0,
+ false /* ownerCanAddInternalSystemWindow */);
+ }
+
+ @Override
+ void reportResized() {
+ super.reportResized();
+ resizeReported = true;
+ }
+
+ @Override
+ public boolean isGoneForLayoutLw() {
+ return false;
+ }
+
+ @Override
+ void updateResizingWindowIfNeeded() {
+ // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive
+ // the system that it can actually update the window.
+ boolean hadSurface = mHasSurface;
+ mHasSurface = true;
+
+ super.updateResizingWindowIfNeeded();
+
+ mHasSurface = hadSurface;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index a9d930f5c893..eaf4ac4baf4f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -19,21 +19,16 @@ package com.android.server.wm;
import static android.view.View.VISIBLE;
import android.app.ActivityManager.TaskDescription;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
-import android.os.Binder;
import android.view.Display;
import android.view.DisplayInfo;
-import android.view.IApplicationToken;
import org.junit.Assert;
import org.junit.After;
import org.junit.Before;
import org.mockito.MockitoAnnotations;
-import android.app.ActivityManager.TaskSnapshot;
import android.content.Context;
-import android.os.IBinder;
import android.support.test.InstrumentationRegistry;
import android.view.IWindow;
import android.view.WindowManager;
@@ -41,10 +36,6 @@ import android.view.WindowManager;
import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.AppOpsManager.OP_NONE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.content.res.Configuration.EMPTY;
-import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -58,7 +49,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.mockito.Mockito.mock;
import com.android.server.AttributeCache;
@@ -78,8 +68,7 @@ class WindowTestsBase {
// make sure we don't collide with any existing display. If we run into no other display, the
// added display should be treated as default. This cannot be the default display
private static int sNextDisplayId = Display.DEFAULT_DISPLAY + 1;
- static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
- private static int sNextTaskId = 0;
+ private static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
private static boolean sOneTimeSetupDone = false;
static DisplayContent sDisplayContent;
@@ -184,14 +173,14 @@ class WindowTestsBase {
private static WindowToken createWindowToken(DisplayContent dc, int stackId, int type) {
if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
- return new TestWindowToken(type, dc);
+ return new WindowTestUtils.TestWindowToken(type, dc);
}
final TaskStack stack = stackId == INVALID_STACK_ID
? createTaskStackOnDisplay(dc)
: createStackControllerOnStackOnDisplay(stackId, dc).mContainer;
final Task task = createTaskInStack(stack, 0 /* userId */);
- final TestAppWindowToken token = new TestAppWindowToken(dc);
+ final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(dc);
task.addChild(token, 0);
return token;
}
@@ -209,7 +198,7 @@ class WindowTestsBase {
}
WindowState createAppWindow(Task task, int type, String name) {
- final AppWindowToken token = new TestAppWindowToken(sDisplayContent);
+ final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
task.addChild(token, 0);
return createWindow(null, type, token, name);
}
@@ -260,10 +249,7 @@ class WindowTestsBase {
/** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
static Task createTaskInStack(TaskStack stack, int userId) {
- final Task newTask = new Task(sNextTaskId++, stack, userId, sWm, null, EMPTY, 0, false,
- false, new TaskDescription(), null);
- stack.addTask(newTask, POSITION_TOP);
- return newTask;
+ return WindowTestUtils.createTaskInStack(sWm, stack, userId);
}
/** Creates a {@link DisplayContent} and adds it to the system. */
@@ -274,227 +260,10 @@ class WindowTestsBase {
return new DisplayContent(display, sWm, sLayersController, new WallpaperController(sWm));
}
- /* Used so we can gain access to some protected members of the {@link WindowToken} class */
- static class TestWindowToken extends WindowToken {
- int adj = 0;
-
- TestWindowToken(int type, DisplayContent dc) {
- this(type, dc, false /* persistOnEmpty */);
- }
-
- TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) {
- super(sWm, mock(IBinder.class), type, persistOnEmpty, dc,
- false /* ownerCanManageAppTokens */);
- }
-
- int getWindowsCount() {
- return mChildren.size();
- }
-
- boolean hasWindow(WindowState w) {
- return mChildren.contains(w);
- }
-
- @Override
- int getAnimLayerAdjustment() {
- return adj;
- }
- }
-
- /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
- static class TestAppWindowToken extends AppWindowToken {
-
- TestAppWindowToken(DisplayContent dc) {
- super(sWm, null, false, dc, true /* fillsParent */, null /* overrideConfig */,
- null /* bounds */);
- }
-
- TestAppWindowToken(WindowManagerService service, IApplicationToken token,
- boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
- boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
- int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
- boolean alwaysFocusable, AppWindowContainerController controller,
- Configuration overrideConfig, Rect bounds) {
- super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen,
- showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges,
- launchTaskBehind, alwaysFocusable, controller, overrideConfig, bounds);
- }
-
- int getWindowsCount() {
- return mChildren.size();
- }
-
- boolean hasWindow(WindowState w) {
- return mChildren.contains(w);
- }
-
- WindowState getFirstChild() {
- return mChildren.getFirst();
- }
-
- WindowState getLastChild() {
- return mChildren.getLast();
- }
-
- int positionInParent() {
- return getParent().mChildren.indexOf(this);
- }
- }
-
- /* Used so we can gain access to some protected members of the {@link Task} class */
- class TestTask extends Task {
-
- boolean mShouldDeferRemoval = false;
- boolean mOnDisplayChangedCalled = false;
- private boolean mUseLocalIsAnimating = false;
- private boolean mIsAnimating = false;
-
- TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
- Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
- boolean homeTask, TaskWindowContainerController controller) {
- super(taskId, stack, userId, service, bounds, overrideConfig, resizeMode,
- supportsPictureInPicture, homeTask, new TaskDescription(), controller);
- }
-
- boolean shouldDeferRemoval() {
- return mShouldDeferRemoval;
- }
-
- int positionInParent() {
- return getParent().mChildren.indexOf(this);
- }
-
- @Override
- void onDisplayChanged(DisplayContent dc) {
- super.onDisplayChanged(dc);
- mOnDisplayChangedCalled = true;
- }
-
- @Override
- boolean isAnimating() {
- return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating();
- }
-
- void setLocalIsAnimating(boolean isAnimating) {
- mUseLocalIsAnimating = true;
- mIsAnimating = isAnimating;
- }
- }
-
- /**
- * Used so we can gain access to some protected members of {@link TaskWindowContainerController}
- * class.
- */
- class TestTaskWindowContainerController extends TaskWindowContainerController {
-
- TestTaskWindowContainerController() {
- this(createStackControllerOnDisplay(sDisplayContent));
- }
-
- TestTaskWindowContainerController(StackWindowController stackController) {
- super(sNextTaskId++, new TaskWindowContainerListener() {
- @Override
- public void onSnapshotChanged(TaskSnapshot snapshot) {
-
- }
-
- @Override
- public void requestResize(Rect bounds, int resizeMode) {
-
- }
- }, stackController, 0 /* userId */, null /* bounds */,
- EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE,
- false /* supportsPictureInPicture */, false /* homeTask*/, true /* toTop*/,
- true /* showForAllUsers */, new TaskDescription(), sWm);
- }
-
- @Override
- TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds,
- Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
- boolean homeTask, TaskDescription taskDescription) {
- return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode,
- supportsPictureInPicture, homeTask, this);
- }
- }
-
- class TestAppWindowContainerController extends AppWindowContainerController {
-
- final IApplicationToken mToken;
-
- TestAppWindowContainerController(TestTaskWindowContainerController taskController) {
- this(taskController, new TestIApplicationToken());
- }
-
- TestAppWindowContainerController(TestTaskWindowContainerController taskController,
- IApplicationToken token) {
- super(taskController, token, null /* listener */, 0 /* index */,
- SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */,
- true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */,
- false /* launchTaskBehind */, false /* alwaysFocusable */,
- 0 /* targetSdkVersion */, 0 /* rotationAnimationHint */,
- 0 /* inputDispatchingTimeoutNanos */, sWm, null /* overrideConfig */,
- null /* bounds */);
- mToken = token;
- }
-
- @Override
- AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
- boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
- boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
- int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
- boolean alwaysFocusable, AppWindowContainerController controller,
- Configuration overrideConfig, Rect bounds) {
- return new TestAppWindowToken(service, token, voiceInteraction, dc,
- inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
- orientation,
- rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
- controller, overrideConfig, bounds);
- }
-
- AppWindowToken getAppWindowToken() {
- return (AppWindowToken) sDisplayContent.getWindowToken(mToken.asBinder());
- }
+ /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
+ WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
+ WindowToken token) {
+ return new WindowTestUtils.TestWindowState(sWm, sMockSession, sIWindow, attrs, token);
}
- class TestIApplicationToken implements IApplicationToken {
-
- private final Binder mBinder = new Binder();
- @Override
- public IBinder asBinder() {
- return mBinder;
- }
- }
-
- /** Used to track resize reports. */
- class TestWindowState extends WindowState {
- boolean resizeReported;
-
- TestWindowState(WindowManager.LayoutParams attrs, WindowToken token) {
- super(sWm, sMockSession, sIWindow, token, null, OP_NONE, 0, attrs, 0, 0,
- false /* ownerCanAddInternalSystemWindow */);
- }
-
- @Override
- void reportResized() {
- super.reportResized();
- resizeReported = true;
- }
-
- @Override
- public boolean isGoneForLayoutLw() {
- return false;
- }
-
- @Override
- void updateResizingWindowIfNeeded() {
- // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive
- // the system that it can actually update the window.
- boolean hadSurface = mHasSurface;
- mHasSurface = true;
-
- super.updateResizingWindowIfNeeded();
-
- mHasSurface = hadSurface;
- }
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index babb6d9db31f..4f7ad41050f1 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -46,7 +46,8 @@ public class WindowTokenTests extends WindowTestsBase {
@Test
public void testAddWindow() throws Exception {
- final TestWindowToken token = new TestWindowToken(0, sDisplayContent);
+ final WindowTestUtils.TestWindowToken token =
+ new WindowTestUtils.TestWindowToken(0, sDisplayContent);
assertEquals(0, token.getWindowsCount());
@@ -76,7 +77,7 @@ public class WindowTokenTests extends WindowTestsBase {
@Test
public void testChildRemoval() throws Exception {
final DisplayContent dc = sDisplayContent;
- final TestWindowToken token = new TestWindowToken(0, dc);
+ final WindowTestUtils.TestWindowToken token = new WindowTestUtils.TestWindowToken(0, dc);
assertEquals(token, dc.getWindowToken(token.token));
@@ -95,7 +96,8 @@ public class WindowTokenTests extends WindowTestsBase {
@Test
public void testAdjustAnimLayer() throws Exception {
- final TestWindowToken token = new TestWindowToken(0, sDisplayContent);
+ final WindowTestUtils.TestWindowToken token =
+ new WindowTestUtils.TestWindowToken(0, sDisplayContent);
final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
@@ -135,8 +137,9 @@ public class WindowTokenTests extends WindowTestsBase {
*/
@Test
public void testTokenRemovalProcess() throws Exception {
- final TestWindowToken token =
- new TestWindowToken(TYPE_TOAST, sDisplayContent, true /* persistOnEmpty */);
+ final WindowTestUtils.TestWindowToken token =
+ new WindowTestUtils.TestWindowToken(TYPE_TOAST, sDisplayContent,
+ true /* persistOnEmpty */);
// Verify that the token is on the display
assertNotNull(sDisplayContent.getWindowToken(token.token));