diff options
32 files changed, 543 insertions, 922 deletions
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 2f87debce978..b9d28e4ce8eb 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -100,7 +100,8 @@ message ActivityStackProto { message TaskRecordProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1; + // To be removed soon. + optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true]; optional int32 id = 2; repeated ActivityRecordProto activities = 3; optional int32 stack_id = 4; @@ -113,6 +114,7 @@ message TaskRecordProto { optional .android.graphics.RectProto bounds = 11; optional int32 min_width = 12; optional int32 min_height = 13; + optional .com.android.server.wm.TaskProto task = 14; } message ActivityRecordProto { diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java index 48a7b73a5fc1..12681133d9c4 100644 --- a/services/core/java/com/android/server/wm/ActivityDisplay.java +++ b/services/core/java/com/android/server/wm/ActivityDisplay.java @@ -41,7 +41,6 @@ import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY; import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE; import static com.android.server.am.ActivityDisplayProto.STACKS; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; @@ -1523,7 +1522,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { final ActivityStack stack = getChildAt(i); final ArrayList<TaskRecord> tasks = stack.getAllTasks(); for (int j = tasks.size() - 1; j >= 0; --j) { - stack.removeTask(tasks.get(j), "removeAllTasks", REMOVE_TASK_MODE_DESTROYING); + stack.removeChild(tasks.get(j), "removeAllTasks"); } } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d4dd033f38e6..b95d3272891d 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1148,56 +1148,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } - // TODO(task-unify): Remove once TaskRecord and Task are unified. TaskRecord getTaskRecord() { 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}. - */ - // TODO(task-unify): Can be remove after task level unification. Callers can just use addChild - void setTask(TaskRecord task) { - // Do nothing if the {@link TaskRecord} is the same as the current {@link getTaskRecord}. - if (task != null && task == getTaskRecord()) { - return; - } - - final ActivityStack oldStack = getActivityStack(); - final ActivityStack newStack = task != null ? task.getStack() : null; - - // Inform old stack (if present) of activity removal and new stack (if set) of activity - // addition. - if (oldStack != newStack) { - if (oldStack != null) { - oldStack.onActivityRemovedFromStack(this); - } - - if (newStack != null) { - newStack.onActivityAddedToStack(this); - } - } - - final TaskRecord oldTask = this.task; - this.task = task; - - // This is attaching the activity to the task which we only want to do once. - // TODO(task-unify): Need to re-work after unifying the task level since it will already - // have a parent then. Just need to restructure the re-parent case not to do this. NOTE that - // the reparenting flag passed in can't be used directly for this as it isn't set in - // ActivityRecord#reparent() case that ends up calling this method. - if (task != null && getParent() == null) { - task.addChild(this); - } else { - onParentChanged(task, oldTask); - } - } - - /** * Sets the Task on this activity for the purposes of re-use during launch where we will * re-use another activity instead of this one for the launch. */ @@ -1220,8 +1175,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { - final TaskRecord oldTask = (oldParent != null) ? ((Task) oldParent).mTaskRecord : null; - final TaskRecord newTask = (newParent != null) ? ((Task) newParent).mTaskRecord : null; + final TaskRecord oldTask = oldParent != null ? (TaskRecord) oldParent : null; + final TaskRecord newTask = newParent != null ? (TaskRecord) newParent : null; this.task = newTask; super.onParentChanged(newParent, oldParent); @@ -1230,14 +1185,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (oldParent == null && newParent != null) { // First time we are adding the activity to the system. - // TODO(task-unify): See if mVoiceInteraction variable is really needed after task level - // unification. - mVoiceInteraction = task.mTaskRecord != null && task.mTaskRecord.voiceSession != null; + mVoiceInteraction = newTask.voiceSession != null; mInputDispatchingTimeoutNanos = getInputDispatchingTimeoutLocked(this) * 1000000L; onDisplayChanged(task.getDisplayContent()); - if (task.mTaskRecord != null) { - task.mTaskRecord.updateOverrideConfigurationFromLaunchBounds(); - } + // TODO(b/36505427): Maybe this call should be moved inside + // updateOverrideConfiguration() + newTask.updateOverrideConfigurationFromLaunchBounds(); // Make sure override configuration is up-to-date before using to create window // controller. updateSizeCompatMode(); @@ -1279,8 +1232,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Inform old stack (if present) of activity removal and new stack (if set) of activity // addition. if (oldStack != newStack) { - // TODO(task-unify): Might be better to use onChildAdded and onChildRemoved signal for - // this once task level is unified. if (oldStack != null) { oldStack.onActivityRemovedFromStack(this); } @@ -1964,15 +1915,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving activity=%s" + " to task=%d at %d", this, task.mTaskId, position); - - reparent(newTask.getTask(), position); - } - - // TODO(task-unify): Remove once Task level is unified. - void onParentChanged(TaskRecord newParent, TaskRecord oldParent) { - onParentChanged( - newParent != null ? newParent.mTask : null, - oldParent != null ? oldParent.mTask : null); + reparent(newTask, position); } private boolean isHomeIntent(Intent intent) { @@ -2051,7 +1994,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A /** * @return Stack value from current task, null if there is no task. */ - // TODO: Remove once ActivityStack and TaskStack are unified. + // TODO(stack-unify): Remove once ActivityStack and TaskStack are unified. <T extends ActivityStack> T getActivityStack() { return task != null ? (T) task.getStack() : null; } @@ -2339,7 +2282,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A /** Finish all activities in the task with the same affinity as this one. */ void finishActivityAffinity() { - final ArrayList<ActivityRecord> activities = getTaskRecord().mActivities; + final ArrayList<ActivityRecord> activities = getTaskRecord().mChildren; for (int index = activities.indexOf(this); index >= 0; --index) { final ActivityRecord cur = activities.get(index); if (!Objects.equals(cur.taskAffinity, taskAffinity)) { @@ -2451,7 +2394,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY, mUserId, System.identityHashCode(this), task.mTaskId, shortComponentName, reason); - final ArrayList<ActivityRecord> activities = task.mActivities; + final ArrayList<ActivityRecord> activities = task.mChildren; final int index = activities.indexOf(this); if (index < (task.getChildCount() - 1)) { if ((intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) { @@ -2505,7 +2448,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // When finishing the activity preemptively take the snapshot before the app window // is marked as hidden and any configuration changes take place if (mAtmService.mWindowManager.mTaskSnapshotController != null) { - final ArraySet<Task> tasks = Sets.newArraySet(task.mTask); + final ArraySet<Task> tasks = Sets.newArraySet(task); mAtmService.mWindowManager.mTaskSnapshotController.snapshotTasks(tasks); mAtmService.mWindowManager.mTaskSnapshotController .addSkipClosingAppSnapshotTasks(tasks); @@ -2547,7 +2490,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // In this case, we can set the visibility of all the task overlay activities when // we detect the last one is finishing to keep them in sync. if (task.onlyHasTaskOverlayActivities(true /* excludeFinishing */)) { - for (ActivityRecord taskOverlay : task.mActivities) { + for (int i = task.getChildCount() - 1; i >= 0 ; --i) { + final ActivityRecord taskOverlay = task.getChildAt(i); if (!taskOverlay.mTaskOverlay) { continue; } @@ -2819,8 +2763,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** Note: call {@link #cleanUp(boolean, boolean)} before this method. */ - // TODO(task-unify): Look into consolidating this with TaskRecord.removeChild once we unify - // task level. void removeFromHistory(String reason) { finishActivityResults(Activity.RESULT_CANCELED, null /* resultData */); makeFinishingLocked(); @@ -4659,7 +4601,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } // Check if position in task allows to become paused - final int positionInTask = task.mActivities.indexOf(this); + final int positionInTask = task.mChildren.indexOf(this); if (positionInTask == -1) { throw new IllegalStateException("Activity not found in its task"); } @@ -5387,7 +5329,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return INVALID_TASK_ID; } final TaskRecord task = r.task; - final int activityNdx = task.mActivities.indexOf(r); + final int activityNdx = task.mChildren.indexOf(r); if (activityNdx < 0 || (onlyRoot && activityNdx > task.findRootIndex(true /* effectiveRoot */))) { return INVALID_TASK_ID; @@ -5751,7 +5693,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override boolean isWaitingForTransitionStart() { final DisplayContent dc = getDisplayContent(); - // TODO: Test for null can be removed once unification is done. + // TODO(display-unify): Test for null can be removed once unification is done. if (dc == null) return false; return dc.mAppTransition.isTransitionSet() && (dc.mOpeningApps.contains(this) @@ -6559,8 +6501,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // If the changes come from change-listener, the incoming parent configuration is // still the old one. Make sure their orientations are the same to reduce computing // the compatibility bounds for the intermediate state. - && (task.mTaskRecord == null || task.mTaskRecord - .getConfiguration().orientation == newParentConfig.orientation)) { + && (task.getConfiguration().orientation == newParentConfig.orientation)) { final Rect taskBounds = task.getBounds(); // Since we only center the activity horizontally, if only the fixed height is smaller // than its container, the override bounds don't need to take effect. @@ -6878,8 +6819,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A preserveWindow &= isResizeOnlyChange(changes); final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged()); if (hasResizeChange) { - final boolean isDragResizing = - getTaskRecord().getTask().isDragResizing(); + final boolean isDragResizing = getTaskRecord().isDragResizing(); mRelaunchReason = isDragResizing ? RELAUNCH_REASON_FREE_RESIZE : RELAUNCH_REASON_WINDOWING_MODE_RESIZE; } else { diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 8e3995bfd872..9dade2cfb037 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -254,7 +254,11 @@ class ActivityStack extends ConfigurationContainer { @Override protected void onParentChanged( ConfigurationContainer newParent, ConfigurationContainer oldParent) { - ActivityDisplay display = getParent(); + if (oldParent != null) { + mPrevDisplayId = ((ActivityDisplay) oldParent).mDisplayId; + } + + final ActivityDisplay display = getParent(); if (display != null) { // Rotations are relative to the display. This means if there are 2 displays rotated // differently (eg. 2 monitors with one landscape and one portrait), moving a stack @@ -292,18 +296,6 @@ class ActivityStack extends ConfigurationContainer { RESTARTING_PROCESS } - @VisibleForTesting - /* The various modes for the method {@link #removeTask}. */ - // Task is being completely removed from all stacks in the system. - protected static final int REMOVE_TASK_MODE_DESTROYING = 0; - // Task is being removed from this stack so we can add it to another stack. In the case we are - // moving we don't want to perform some operations on the task like removing it from window - // manager or recents. - static final int REMOVE_TASK_MODE_MOVING = 1; - // Similar to {@link #REMOVE_TASK_MODE_MOVING} and the task will be added to the top of its new - // stack and the new stack will be on top of all stacks. - static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2; - final ActivityTaskManagerService mService; final WindowManagerService mWindowManager; @@ -381,6 +373,8 @@ class ActivityStack extends ConfigurationContainer { final int mStackId; /** The attached Display's unique identifier, or -1 if detached */ int mDisplayId; + // Id of the previous display the stack was on. + int mPrevDisplayId = INVALID_DISPLAY; /** Stores the override windowing-mode from before a transient mode change (eg. split) */ private int mRestoreOverrideWindowingMode = WINDOWING_MODE_UNDEFINED; @@ -962,7 +956,7 @@ class ActivityStack extends ConfigurationContainer { void positionChildWindowContainerAtTop(TaskRecord child) { if (mTaskStack != null) { // TODO: Remove after unification. This cannot be false after that. - mTaskStack.positionChildAtTop(child.getTask(), true /* includingParents */); + mTaskStack.positionChildAtTop(child, true /* includingParents */); } } @@ -974,7 +968,7 @@ class ActivityStack extends ConfigurationContainer { child.getStack(), true /* ignoreCurrent */); if (mTaskStack != null) { // TODO: Remove after unification. This cannot be false after that. - mTaskStack.positionChildAtBottom(child.getTask(), + mTaskStack.positionChildAtBottom(child, nextFocusableStack == null /* includingParents */); } } @@ -1168,7 +1162,7 @@ class ActivityStack extends ConfigurationContainer { } final TaskRecord task = r.getTaskRecord(); final ActivityStack stack = r.getActivityStack(); - if (stack != null && task.mActivities.contains(r) && mTaskHistory.contains(task)) { + if (stack != null && task.mChildren.contains(r) && mTaskHistory.contains(task)) { if (stack != this) Slog.w(TAG, "Illegal state! task does not point to stack it is in."); return r; @@ -1183,7 +1177,8 @@ class ActivityStack extends ConfigurationContainer { /** Checks if there are tasks with specific UID in the stack. */ boolean isUidPresent(int uid) { for (TaskRecord task : mTaskHistory) { - for (ActivityRecord r : task.mActivities) { + for (int i = task.getChildCount() - 1; i >= 0 ; --i) { + final ActivityRecord r = task.getChildAt(i); if (r.getUid() == uid) { return true; } @@ -1195,7 +1190,8 @@ class ActivityStack extends ConfigurationContainer { /** Get all UIDs that are present in the stack. */ void getPresentUIDs(IntArray presentUIDs) { for (TaskRecord task : mTaskHistory) { - for (ActivityRecord r : task.mActivities) { + for (int i = task.getChildCount() - 1; i >= 0 ; --i) { + final ActivityRecord r = task.getChildAt(i); presentUIDs.add(r.getUid()); } } @@ -1207,12 +1203,6 @@ class ActivityStack extends ConfigurationContainer { return display != null && display.isSingleTaskInstance(); } - private void removeActivitiesFromLRUList(TaskRecord task) { - for (ActivityRecord r : task.mActivities) { - mLRUActivities.remove(r); - } - } - /** @return {@code true} if LRU list contained the specified activity. */ final boolean removeActivityFromLRUList(ActivityRecord activity) { return mLRUActivities.remove(activity); @@ -3016,19 +3006,19 @@ class ActivityStack extends ConfigurationContainer { mTaskHistory.remove(task); mTaskHistory.add(position, task); if (mTaskStack != null) { - // TODO: this could not be false after unification. - mTaskStack.positionChildAt(task.getTask(), position); + // TODO: this can not be false after unification Stack. + mTaskStack.positionChildAt(task, position); } - updateTaskMovement(task, true); + task.updateTaskMovement(true); } - private void insertTaskAtTop(TaskRecord task, ActivityRecord starting) { - // TODO: Better place to put all the code below...may be addTask... + void insertTaskAtTop(TaskRecord task, ActivityRecord starting) { + // TODO: Better place to put all the code below...may be addChild... mTaskHistory.remove(task); // Now put task at top. final int position = getAdjustedPositionForTask(task, mTaskHistory.size(), starting); mTaskHistory.add(position, task); - updateTaskMovement(task, true); + task.updateTaskMovement(true); positionChildWindowContainerAtTop(task); } @@ -3036,7 +3026,7 @@ class ActivityStack extends ConfigurationContainer { mTaskHistory.remove(task); final int position = getAdjustedPositionForTask(task, 0, null); mTaskHistory.add(position, task); - updateTaskMovement(task, true); + task.updateTaskMovement(true); positionChildWindowContainerAtBottom(task); } @@ -3070,7 +3060,7 @@ class ActivityStack extends ConfigurationContainer { if (!startIt) { if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task " + task, new RuntimeException("here").fillInStackTrace()); - r.setTask(rTask); + rTask.positionChildAtTop(r); ActivityOptions.abort(options); return; } @@ -3097,7 +3087,7 @@ class ActivityStack extends ConfigurationContainer { // Slot the activity into the history stack and proceed if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task, new RuntimeException("here").fillInStackTrace()); - r.setTask(task); + task.positionChildAtTop(r); // The transition animation and starting window are not needed if {@code allowMoveToFront} // is false, because the activity won't be visible. @@ -3272,7 +3262,7 @@ class ActivityStack extends ConfigurationContainer { // with the same affinity is unlikely to be in the same stack. final TaskRecord targetTask; final ActivityRecord bottom = - !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ? + !mTaskHistory.isEmpty() && mTaskHistory.get(0).hasChild() ? mTaskHistory.get(0).getChildAt(0) : null; if (bottom != null && target.taskAffinity.equals(bottom.getTaskRecord().affinity)) { // If the activity currently at the bottom has the @@ -3483,7 +3473,7 @@ class ActivityStack extends ConfigurationContainer { // instance of the same activity? Then we drop the instance // below so it remains singleTop. if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) { - final ArrayList<ActivityRecord> taskActivities = task.mActivities; + final ArrayList<ActivityRecord> taskActivities = task.mChildren; final int targetNdx = taskActivities.indexOf(target); if (targetNdx > 0) { final ActivityRecord p = taskActivities.get(targetNdx - 1); @@ -3637,7 +3627,7 @@ class ActivityStack extends ConfigurationContainer { finishedTask = r.getTaskRecord(); int taskNdx = mTaskHistory.indexOf(finishedTask); final TaskRecord task = finishedTask; - int activityNdx = task.mActivities.indexOf(r); + int activityNdx = task.mChildren.indexOf(r); getDisplay().mDisplayContent.prepareAppTransition( TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */); r.finishIfPossible(reason, false /* oomAdj */); @@ -3774,7 +3764,7 @@ class ActivityStack extends ConfigurationContainer { final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode, Intent resultData) { final TaskRecord task = srec.getTaskRecord(); - final ArrayList<ActivityRecord> activities = task.mActivities; + final ArrayList<ActivityRecord> activities = task.mChildren; final int start = activities.indexOf(srec); if (!mTaskHistory.contains(task) || (start < 0)) { return false; @@ -3868,8 +3858,16 @@ class ActivityStack extends ConfigurationContainer { * an activity moves away from the stack. */ void onActivityRemovedFromStack(ActivityRecord r) { + removeActivityFromLRUList(r); removeTimeoutsForActivity(r); + // TODO(stack-unify): null check will no longer be needed. + if (mTaskStack != null) { + mTaskStack.mExitingActivities.remove(r); + } + // TODO(stack-unify): Remove if no bugs showed up... + //r.mIsExiting = false; + if (mResumedActivity != null && mResumedActivity == r) { setResumedActivity(null, "onActivityRemovedFromStack"); } @@ -4062,7 +4060,7 @@ class ActivityStack extends ConfigurationContainer { if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Removing app " + app + " from history with " + i + " entries"); for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; + final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mChildren; mTmpActivities.clear(); mTmpActivities.addAll(activities); @@ -4151,19 +4149,6 @@ class ActivityStack extends ConfigurationContainer { getDisplay().mDisplayContent.prepareAppTransition(transit, false); } - private void updateTaskMovement(TaskRecord task, boolean toFront) { - if (task.isPersistable) { - task.mLastTimeMoved = System.currentTimeMillis(); - // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most - // recently will be most negative, tasks sent to the bottom before that will be less - // negative. Similarly for recent tasks moved to the top which will be most positive. - if (!toFront) { - task.mLastTimeMoved *= -1; - } - } - mRootActivityContainer.invalidateTaskLayers(); - } - final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options, AppTimeTracker timeTracker, String reason) { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr); @@ -4296,7 +4281,7 @@ class ActivityStack extends ConfigurationContainer { mTaskHistory.remove(tr); mTaskHistory.add(0, tr); - updateTaskMovement(tr, false); + tr.updateTaskMovement(false); getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false); moveToBack("moveTaskToBackLocked", tr); @@ -4335,7 +4320,7 @@ class ActivityStack extends ConfigurationContainer { for (int taskIndex = mTaskHistory.indexOf(startTask); taskIndex >= 0; --taskIndex) { final TaskRecord task = mTaskHistory.get(taskIndex); - final ArrayList<ActivityRecord> activities = task.mActivities; + final ArrayList<ActivityRecord> activities = task.mChildren; int activityIndex = (start.getTaskRecord() == task) ? activities.indexOf(start) : activities.size() - 1; for (; activityIndex >= 0; --activityIndex) { @@ -4375,10 +4360,10 @@ class ActivityStack extends ConfigurationContainer { final TaskRecord task = mTaskHistory.get(i); if (task.isResizeable()) { if (tempTaskInsetBounds != null && !tempTaskInsetBounds.isEmpty()) { - task.setDisplayedBounds(taskBounds); + task.setOverrideDisplayedBounds(taskBounds); task.setBounds(tempTaskInsetBounds); } else { - task.setDisplayedBounds(null); + task.setOverrideDisplayedBounds(null); task.setBounds(taskBounds); } } @@ -4430,9 +4415,9 @@ class ActivityStack extends ConfigurationContainer { for (int i = mTaskHistory.size() - 1; i >= 0; i--) { final TaskRecord task = mTaskHistory.get(i); if (bounds == null || bounds.isEmpty()) { - task.setDisplayedBounds(null); + task.setOverrideDisplayedBounds(null); } else if (task.isResizeable()) { - task.setDisplayedBounds(bounds); + task.setOverrideDisplayedBounds(bounds); } } } @@ -4477,7 +4462,7 @@ class ActivityStack extends ConfigurationContainer { TaskRecord lastTask = null; ComponentName homeActivity = null; for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; + final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mChildren; mTmpActivities.clear(); mTmpActivities.addAll(activities); @@ -4675,7 +4660,7 @@ class ActivityStack extends ConfigurationContainer { pw.println(prefix + "mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds); pw.println(prefix + "* " + task); task.dump(pw, prefix + " "); - dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mActivities, + dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mChildren, prefix, "Hist", true, !dumpAll, dumpClient, dumpPackage, false, null, task); } return true; @@ -4686,15 +4671,15 @@ class ActivityStack extends ConfigurationContainer { if ("all".equals(name)) { for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - activities.addAll(mTaskHistory.get(taskNdx).mActivities); + activities.addAll(mTaskHistory.get(taskNdx).mChildren); } } else if ("top".equals(name)) { final int top = mTaskHistory.size() - 1; if (top >= 0) { - final ArrayList<ActivityRecord> list = mTaskHistory.get(top).mActivities; - int listTop = list.size() - 1; + final TaskRecord task = mTaskHistory.get(top); + int listTop = task.getChildCount() - 1; if (listTop >= 0) { - activities.add(list.get(listTop)); + activities.add(task.getChildAt(listTop)); } } } else { @@ -4702,7 +4687,9 @@ class ActivityStack extends ConfigurationContainer { matcher.build(name); for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - for (ActivityRecord r1 : mTaskHistory.get(taskNdx).mActivities) { + final TaskRecord task = mTaskHistory.get(taskNdx); + for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) { + final ActivityRecord r1 = task.getChildAt(activityNdx); if (matcher.match(r1, r1.intent.getComponent())) { activities.add(r1); } @@ -4734,58 +4721,51 @@ class ActivityStack extends ConfigurationContainer { return starting; } - /** - * Removes the input task from this stack. - * - * @param task to remove. - * @param reason for removal. - * @param mode task removal mode. Either {@link #REMOVE_TASK_MODE_DESTROYING}, - * {@link #REMOVE_TASK_MODE_MOVING}, {@link #REMOVE_TASK_MODE_MOVING_TO_TOP}. - */ - void removeTask(TaskRecord task, String reason, int mode) { - if (!mTaskHistory.remove(task)) { - // Not really in this stack anymore... - return; + // TODO(stack-unify): Merge into removeChild method below. + void onChildRemoved(TaskRecord child, DisplayContent dc) { + mTaskHistory.remove(child); + EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, child.mTaskId, mStackId); + + ActivityDisplay display = getDisplay(); + if (display == null && dc != null) { + display = dc.mActivityDisplay; } - EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, task.mTaskId, getStackId()); + if (display.isSingleTaskInstance()) { + mService.notifySingleTaskDisplayEmpty(display.mDisplayId); + } - removeActivitiesFromLRUList(task); - updateTaskMovement(task, true); + display.mDisplayContent.setLayoutNeeded(); - if (mode == REMOVE_TASK_MODE_DESTROYING) { - task.cleanUpResourcesForDestroy(); + if (mTaskHistory.isEmpty()) { + // Stack is now empty... + remove(); } + } + /** + * Removes the input task from this stack. + * + * @param task to remove. + * @param reason for removal. + */ + void removeChild(TaskRecord task, String reason) { final ActivityDisplay display = getDisplay(); - if (mTaskHistory.isEmpty()) { - if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this); + final boolean topFocused = mRootActivityContainer.isTopDisplayFocusedStack(this); + mTaskStack.removeChild(task); + moveHomeStackToFrontIfNeeded(topFocused, display, reason); + } + + void moveHomeStackToFrontIfNeeded( + boolean wasTopFocusedStack, ActivityDisplay display, String reason) { + if (mTaskHistory.isEmpty() && wasTopFocusedStack) { // We only need to adjust focused stack if this stack is in focus and we are not in the // process of moving the task to the top of the stack that will be focused. - if (mode != REMOVE_TASK_MODE_MOVING_TO_TOP - && mRootActivityContainer.isTopDisplayFocusedStack(this)) { - String myReason = reason + " leftTaskHistoryEmpty"; - if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) { - display.moveHomeStackToFront(myReason); - } - } - if (isAttached()) { - display.positionChildAtBottom(this); - } - if (!isActivityTypeHome() || !isAttached()) { - remove(); + String myReason = reason + " leftTaskHistoryEmpty"; + if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) { + display.moveHomeStackToFront(myReason); } } - - task.setStack(null); - - // Notify if a task from the pinned stack is being removed (or moved depending on the mode) - if (inPinnedWindowingMode()) { - mService.getTaskChangeNotificationController().notifyActivityUnpinned(); - } - if (display != null && display.isSingleTaskInstance()) { - mService.notifySingleTaskDisplayEmpty(display.mDisplayId); - } } TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent, @@ -4800,9 +4780,9 @@ class ActivityStack extends ConfigurationContainer { boolean toTop, ActivityRecord activity, ActivityRecord source, ActivityOptions options) { final TaskRecord task = TaskRecord.create( - mService, taskId, info, intent, voiceSession, voiceInteractor); + mService, taskId, info, intent, voiceSession, voiceInteractor, this); // add the task to stack first, mTaskPositioner might need the stack association - addTask(task, toTop, "createTaskRecord"); + addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); final int displayId = mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY; final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController() .isKeyguardOrAodShowing(displayId); @@ -4811,7 +4791,6 @@ class ActivityStack extends ConfigurationContainer { && !matchParentBounds() && task.isResizeable() && !isLockscreenShown) { task.setBounds(getRequestedOverrideBounds()); } - task.createTask(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); return task; } @@ -4819,34 +4798,31 @@ class ActivityStack extends ConfigurationContainer { return new ArrayList<>(mTaskHistory); } - void addTask(final TaskRecord task, final boolean toTop, String reason) { - addTask(task, toTop ? MAX_VALUE : 0, true /* schedulePictureInPictureModeChange */, reason); - if (toTop) { - // TODO: figure-out a way to remove this call. - positionChildWindowContainerAtTop(task); - } + // TODO(stack-unify): Merge with addChild below. + void onChildAdded(TaskRecord task, int position) { + final boolean toTop = position >= mTaskHistory.size(); + mTaskHistory.add(position, task); + + // TODO: Feels like this should go in TaskRecord#onParentChanged + task.updateTaskMovement(toTop); } - // TODO: This shouldn't allow automatic reparenting. Remove the call to preAddTask and deal - // with the fall-out... - void addTask(final TaskRecord task, int position, boolean schedulePictureInPictureModeChange, - String reason) { - // TODO: Is this remove really needed? Need to look into the call path for the other addTask - mTaskHistory.remove(task); + void addChild(final TaskRecord task, final boolean toTop, boolean showForAllUsers) { if (isSingleTaskInstance() && !mTaskHistory.isEmpty()) { throw new IllegalStateException("Can only have one child on stack=" + this); } - position = getAdjustedPositionForTask(task, position, null /* starting */); - final boolean toTop = position >= mTaskHistory.size(); - final ActivityStack prevStack = preAddTask(task, reason, toTop); - - mTaskHistory.add(position, task); - task.setStack(this); + final int position = + getAdjustedPositionForTask(task, toTop ? MAX_VALUE : 0, null /* starting */); - updateTaskMovement(task, toTop); + // We only want to move the parents to the parents if we are creating this task at the + // top of its stack. + mTaskStack.addChild(task, position, showForAllUsers, toTop /*moveParents*/); - postAddTask(task, prevStack, schedulePictureInPictureModeChange); + if (toTop) { + // TODO: figure-out a way to remove this call. + positionChildWindowContainerAtTop(task); + } } void positionChildAt(TaskRecord task, int index) { @@ -4861,8 +4837,14 @@ class ActivityStack extends ConfigurationContainer { final ActivityRecord topRunningActivity = task.topRunningActivityLocked(); final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity; insertTaskAtPosition(task, index); - task.setStack(this); - postAddTask(task, null /* prevStack */, true /* schedulePictureInPictureModeChange */); + + // TODO: Investigate if this random code is really needed. + if (task.voiceSession != null) { + try { + task.voiceSession.taskStarted(task.intent, task.mTaskId); + } catch (RemoteException e) { + } + } if (wasResumed) { if (mResumedActivity != null) { @@ -4879,32 +4861,6 @@ class ActivityStack extends ConfigurationContainer { mRootActivityContainer.resumeFocusedStacksTopActivities(); } - private ActivityStack preAddTask(TaskRecord task, String reason, boolean toTop) { - final ActivityStack prevStack = task.getStack(); - if (prevStack != null && prevStack != this) { - prevStack.removeTask(task, reason, - toTop ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING); - } - return prevStack; - } - - /** - * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode - * change. Callers may set this to false if they are explicitly scheduling PiP mode - * changes themselves, like during the PiP animation - */ - private void postAddTask(TaskRecord task, ActivityStack prevStack, - boolean schedulePictureInPictureModeChange) { - if (schedulePictureInPictureModeChange && prevStack != null) { - mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, prevStack); - } else if (task.voiceSession != null) { - try { - task.voiceSession.taskStarted(task.intent, task.mTaskId); - } catch (RemoteException e) { - } - } - } - public void setAlwaysOnTop(boolean alwaysOnTop) { if (isAlwaysOnTop() == alwaysOnTop) { return; diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index dc3d2631a5d7..f8a7397f10df 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -52,7 +52,6 @@ import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE; @@ -83,6 +82,7 @@ import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; +import static com.android.server.wm.WindowContainer.POSITION_TOP; import android.Manifest; import android.app.Activity; @@ -1420,7 +1420,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // WM resizeTask must be done after the task is moved to the correct stack, // because Task's setBounds() also updates dim layer's bounds, but that has // dependency on the stack. - task.resizeWindowContainer(); + task.resize(false /* relayout */, false /* forced */); } } @@ -1885,26 +1885,22 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { final ActivityStack stack = mRootActivityContainer.getLaunchStack(null, aOptions, task, onTop); final ActivityStack currentStack = task.getStack(); + + if (currentStack == stack) { + // Nothing else to do since it is already restored in the right stack. + return true; + } + if (currentStack != null) { - // Task has already been restored once. See if we need to do anything more - if (currentStack == stack) { - // Nothing else to do since it is already restored in the right stack. - return true; - } - // Remove current stack association, so we can re-associate the task with the - // right stack below. - currentStack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING); + // Task has already been restored once. Just re-parent it to the new stack. + task.reparent(stack.mTaskStack, + POSITION_TOP, true /*moveParents*/, "restoreRecentTaskLocked"); + return true; } - stack.addTask(task, onTop, "restoreRecentTask"); - // TODO: move call for creation here and other place into Stack.addTask() - task.createTask(onTop, true /* showForAllUsers */); + stack.addChild(task, onTop, true /* showForAllUsers */); if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Added restored task=" + task + " to stack=" + stack); - for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) { - final ActivityRecord r = task.getChildAt(activityNdx); - r.setTask(task); - } return true; } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index d1bb2559e5be..6edcb0298938 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -50,6 +50,7 @@ import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS; +import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; @@ -1842,7 +1843,7 @@ class ActivityStarter { // {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The task // reference is needed in the call below to {@link setTargetStackAndMoveToFrontIfNeeded} if (targetTaskTop.getTaskRecord() == null) { - targetTaskTop.setTask(targetTask); + targetTask.addChild(targetTaskTop); } if (top != null) { @@ -1862,8 +1863,8 @@ class ActivityStarter { // Go ahead and reset it. mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */, mLaunchFlags, mOptions); - mTargetStack.addTask(targetTask, - !mLaunchTaskBehind /* toTop */, "complyActivityFlags"); + mTargetStack.addChild(targetTask, !mLaunchTaskBehind /* toTop */, + (mStartActivity.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); } } } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) == 0 && !mAddingToTask diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 222f26edaf5d..da7af5fdd369 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -85,7 +85,6 @@ import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.Scr import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE; import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; @@ -1996,7 +1995,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return false; } final TaskRecord task = r.getTaskRecord(); - int index = task.mActivities.lastIndexOf(r); + int index = task.mChildren.lastIndexOf(r); if (index > 0) { ActivityRecord under = task.getChildAt(index - 1); under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null; @@ -2221,18 +2220,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found"); return rect; } - if (task.getStack() != null) { - // Return the bounds from window manager since it will be adjusted for various - // things like the presense of a docked stack for tasks that aren't resizeable. - task.getWindowContainerBounds(rect); - } else { - // Task isn't in window manager yet since it isn't associated with a stack. - // Return the persist value from activity manager - if (!task.matchParentBounds()) { - rect.set(task.getBounds()); - } else if (task.mLastNonFullscreenBounds != null) { - rect.set(task.mLastNonFullscreenBounds); - } + if (task.getParent() != null) { + rect.set(task.getBounds()); + } else if (task.mLastNonFullscreenBounds != null) { + rect.set(task.mLastNonFullscreenBounds); } } } finally { @@ -2249,7 +2240,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final TaskRecord tr = mRootActivityContainer.anyTaskForId(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (tr != null) { - return tr.mTaskDescription; + return tr.getTaskDescription(); } } return null; @@ -3168,10 +3159,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { null /* voiceSession */, null /* voiceInteractor */, !ON_TOP); if (!mRecentTasks.addToBottom(task)) { // The app has too many tasks already and we can't add any more - stack.removeTask(task, "addAppTask", REMOVE_TASK_MODE_DESTROYING); + stack.removeChild(task, "addAppTask"); return INVALID_TASK_ID; } - task.mTaskDescription.copyFrom(description); + task.getTaskDescription().copyFrom(description); // TODO: Send the thumbnail to WM to store it. @@ -4489,7 +4480,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found"); return; } - task.cancelWindowTransition(); + task.cancelTaskWindowTransition(); } } finally { Binder.restoreCallingIdentity(ident); diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index 8b4f7cc571f8..30f3bc5e70fb 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -134,9 +134,9 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { onConfigurationChanged(newParentConfig, true /*forwardToChildren*/); } - // TODO: Consolidate with onConfigurationChanged() method above once unification is done. This - // is only currently need during the process of unification where we don't want configuration - // forwarded to a child from both parents. + // TODO(root-unify): Consolidate with onConfigurationChanged() method above once unification is + // done. This is only currently need during the process of unification where we don't want + // configuration forwarded to a child from both parents. public void onConfigurationChanged(Configuration newParentConfig, boolean forwardToChildren) { mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration); resolveOverrideConfiguration(newParentConfig); diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 2dae12642be3..01cbc5d1e880 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -211,9 +211,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // If there are multiple tasks in the target stack (ie. the home stack, with 3p // and default launchers coexisting), then move the task to the top as a part of // moving the stack to the front - if (targetStack.topTask() != targetActivity.getTaskRecord()) { - targetStack.addTask(targetActivity.getTaskRecord(), true /* toTop */, - "startRecentsActivity"); + final TaskRecord task = targetActivity.getTaskRecord(); + if (targetStack.topTask() != task) { + targetStack.insertTaskAtTop(task, targetActivity); } } else { // No recents activity, create the new recents activity bottom most diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index 51a3e7205489..dc78922ef4fc 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -1265,8 +1265,7 @@ class RootActivityContainer extends ConfigurationContainer : task.realActivity != null ? task.realActivity.flattenToString() : task.getTopActivity() != null ? task.getTopActivity().packageName : "unknown"; - taskBounds[i] = new Rect(); - task.getWindowContainerBounds(taskBounds[i]); + taskBounds[i] = mService.getTaskBounds(task.mTaskId); taskUserIds[i] = task.mUserId; } info.taskIds = taskIds; @@ -1876,7 +1875,12 @@ class RootActivityContainer extends ConfigurationContainer ActivityStack getNextFocusableStack(@NonNull ActivityStack currentFocus, boolean ignoreCurrent) { // First look for next focusable stack on the same display - final ActivityDisplay preferredDisplay = currentFocus.getDisplay(); + ActivityDisplay preferredDisplay = currentFocus.getDisplay(); + if (preferredDisplay == null) { + // Stack is currently detached because it is being removed. Use the previous display it + // was on. + preferredDisplay = getActivityDisplay(currentFocus.mPrevDisplayId); + } final ActivityStack preferredFocusableStack = preferredDisplay.getNextFocusableStack( currentFocus, ignoreCurrent); if (preferredFocusableStack != null) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index f5d3affa89ef..149bcfb991ea 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -206,7 +206,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } @Override - void onChildPositionChanged() { + void onChildPositionChanged(WindowContainer child) { mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, !mWmService.mPerDisplayFocusEnabled /* updateInputWindows */); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 634990b5fdf2..dce15bc8acf8 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.ActivityTaskManager.INVALID_STACK_ID; import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION; import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; @@ -24,6 +25,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.res.Configuration.EMPTY; import static android.view.SurfaceControl.METADATA_TASK_ID; +import static com.android.server.EventLogTags.WM_TASK_CREATED; import static com.android.server.EventLogTags.WM_TASK_REMOVED; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; import static com.android.server.wm.TaskProto.APP_WINDOW_TOKENS; @@ -63,17 +65,21 @@ import java.util.function.Consumer; class Task extends WindowContainer<ActivityRecord> implements ConfigurationContainerListener{ static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM; + final ActivityTaskManagerService mAtmService; + // TODO: Track parent marks like this in WindowContainer. TaskStack mStack; /* Unique identifier for this task. */ final int mTaskId; /* User for which this task was created. */ - final int mUserId; + // TODO: Make final + int mUserId; final Rect mPreparedFrozenBounds = new Rect(); final Configuration mPreparedFrozenMergedConfig = new Configuration(); // If non-empty, bounds used to display the task during animations/interactions. + // TODO(b/119687367): This member is temporary. private final Rect mOverrideDisplayedBounds = new Rect(); /** ID of the display which rotation {@link #mRotation} has. */ @@ -90,11 +96,12 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta private Rect mTmpRect2 = new Rect(); // Resize mode of the task. See {@link ActivityInfo#resizeMode} - private int mResizeMode; + // Based on the {@link ActivityInfo#resizeMode} of the root activity. + int mResizeMode; - // Whether the task supports picture-in-picture. - // See {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} - private boolean mSupportsPictureInPicture; + // Whether or not this task and its activities support PiP. Based on the + // {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag of the root activity. + boolean mSupportsPictureInPicture; // Whether the task is currently being drag-resized private boolean mDragResizing; @@ -116,40 +123,23 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta /** @see #setCanAffectSystemUiFlags */ private boolean mCanAffectSystemUiFlags = true; - // TODO: remove after unification - TaskRecord mTaskRecord; - - // TODO: Remove after unification. - @Override - public void onConfigurationChanged(Configuration newParentConfig, boolean forwardToChildren) { - // Forward configuration changes in cases - // - children won't get it from TaskRecord - // - it's a pinned task - forwardToChildren &= (mTaskRecord == null) || inPinnedWindowingMode(); - super.onConfigurationChanged(newParentConfig, forwardToChildren); - } - - Task(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode, - boolean supportsPictureInPicture, TaskDescription taskDescription, - TaskRecord taskRecord) { - super(service); + Task(int taskId, TaskStack stack, int userId, int resizeMode, boolean supportsPictureInPicture, + TaskDescription taskDescription, ActivityTaskManagerService atm) { + super(atm.mWindowManager); + mAtmService = atm; mTaskId = taskId; mStack = stack; mUserId = userId; mResizeMode = resizeMode; mSupportsPictureInPicture = supportsPictureInPicture; - mTaskRecord = taskRecord; mTaskDescription = taskDescription; + EventLog.writeEvent(WM_TASK_CREATED, mTaskId, + stack != null ? stack.mStackId : INVALID_STACK_ID); // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED). setOrientation(SCREEN_ORIENTATION_UNSET); - if (mTaskRecord != null) { - // This can be null when we call createTaskInStack in WindowTestUtils. Remove this after - // unification. - mTaskRecord.registerConfigurationChangeListener(this); - } else { - setBounds(getResolvedOverrideBounds()); - } + // TODO(task-merge): Is this really needed? + setBounds(getResolvedOverrideBounds()); } @Override @@ -157,37 +147,40 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta return mStack != null ? mStack.getDisplayContent() : null; } - private int getAdjustedAddPosition(int suggestedPosition) { - final int size = mChildren.size(); - if (suggestedPosition >= size) { - return Math.min(size, suggestedPosition); + int getAdjustedAddPosition(ActivityRecord r, int suggestedPosition) { + int maxPosition = mChildren.size(); + if (!r.mTaskOverlay) { + // We want to place all non-overlay activities below overlays. + while (maxPosition > 0) { + final ActivityRecord current = mChildren.get(maxPosition - 1); + if (current.mTaskOverlay && !current.removed) { + --maxPosition; + continue; + } + break; + } + if (maxPosition < 0) { + maxPosition = 0; + } } - for (int pos = 0; pos < size && pos < suggestedPosition; ++pos) { + if (suggestedPosition >= maxPosition) { + return Math.min(maxPosition, suggestedPosition); + } + + for (int pos = 0; pos < maxPosition && pos < suggestedPosition; ++pos) { // TODO: Confirm that this is the behavior we want long term. if (mChildren.get(pos).removed) { // suggestedPosition assumes removed tokens are actually gone. ++suggestedPosition; } } - return Math.min(size, suggestedPosition); - } - - @Override - void addChild(ActivityRecord child, int position) { - position = getAdjustedAddPosition(position); - super.addChild(child, position); - - // Inform the TaskRecord side of the child addition - // TODO(task-unify): Will be removed after task unification. - if (mTaskRecord != null) { - mTaskRecord.onChildAdded(child, position); - } + return Math.min(maxPosition, suggestedPosition); } @Override void positionChildAt(int position, ActivityRecord child, boolean includingParents) { - position = getAdjustedAddPosition(position); + position = getAdjustedAddPosition(child, position); super.positionChildAt(position, child, includingParents); } @@ -222,47 +215,34 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta void removeImmediately() { if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId); EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask"); - if (mTaskRecord != null) { - mTaskRecord.unregisterConfigurationChangeListener(this); - } - super.removeImmediately(); } - void reparent(TaskStack stack, int position, boolean moveParents) { - if (stack == mStack) { - throw new IllegalArgumentException( - "task=" + this + " already child of stack=" + mStack); - } - if (stack == null) { - throw new IllegalArgumentException("reparent: could not find stack."); - } + // TODO: Consolidate this with TaskRecord.reparent() + void reparent(TaskStack stack, int position, boolean moveParents, String reason) { if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId + " from stack=" + mStack); EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask"); - final DisplayContent prevDisplayContent = getDisplayContent(); - - // If we are moving from the fullscreen stack to the pinned stack - // then we want to preserve our insets so that there will not - // be a jump in the area covered by system decorations. We rely - // on the pinned animation to later unset this value. - if (stack.inPinnedWindowingMode()) { - mPreserveNonFloatingState = true; - } else { - mPreserveNonFloatingState = false; - } - getParent().removeChild(this); - stack.addTask(this, position, showForAllUsers(), moveParents); + final ActivityStack prevStack = mStack.mActivityStack; + final boolean wasTopFocusedStack = + mAtmService.mRootActivityContainer.isTopDisplayFocusedStack(prevStack); + final ActivityDisplay prevStackDisplay = prevStack.getDisplay(); - // Relayout display(s). - final DisplayContent displayContent = stack.getDisplayContent(); - displayContent.setLayoutNeeded(); - if (prevDisplayContent != displayContent) { - onDisplayChanged(displayContent); - prevDisplayContent.setLayoutNeeded(); + reparent(stack, position); + + if (!moveParents) { + // Only move home stack forward if we are not going to move the new parent forward. + prevStack.moveHomeStackToFrontIfNeeded(wasTopFocusedStack, prevStackDisplay, reason); } - getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); + + mStack = stack; + stack.positionChildAt(position, this, moveParents); + + // If we are moving from the fullscreen stack to the pinned stack then we want to preserve + // our insets so that there will not be a jump in the area covered by system decorations. + // We rely on the pinned animation to later unset this value. + mPreserveNonFloatingState = stack.inPinnedWindowingMode(); } /** @see ActivityTaskManagerService#positionTaskInStack(int, int, int). */ @@ -270,46 +250,6 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta mStack.positionChildAt(position, this, false /* includingParents */); } - @Override - void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { - super.onParentChanged(newParent, oldParent); - - // Update task bounds if needed. - adjustBoundsForDisplayChangeIfNeeded(getDisplayContent()); - - if (getWindowConfiguration().windowsAreScaleable()) { - // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them - // while a resize is pending. - forceWindowsScaleable(true /* force */); - } else { - forceWindowsScaleable(false /* force */); - } - } - - @Override - void removeChild(ActivityRecord child) { - if (!mChildren.contains(child)) { - Slog.e(TAG, "removeChild: token=" + this + " not found."); - return; - } - - super.removeChild(child); - - // Inform the TaskRecord side of the child removal - // TODO(task-unify): Will be removed after task unification. - if (mTaskRecord != null) { - mTaskRecord.onChildRemoved(child); - } - - // TODO(task-unify): Need to make this account for what we are doing in - // ActivityRecord.removeFromHistory so that the task isn't removed in some situations when - // we unify task level. - if (mChildren.isEmpty()) { - EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeActivity: last activity"); - removeIfPossible(); - } - } - void setSendingToBottom(boolean toBottom) { for (int appTokenNdx = 0; appTokenNdx < mChildren.size(); appTokenNdx++) { mChildren.get(appTokenNdx).sendingToBottom = toBottom; @@ -331,7 +271,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta @Override public int setBounds(Rect bounds) { int rotation = Surface.ROTATION_0; - final DisplayContent displayContent = mStack.getDisplayContent(); + final DisplayContent displayContent = mStack != null ? mStack.getDisplayContent() : null; if (displayContent != null) { rotation = displayContent.getDisplayInfo().rotation; } else if (bounds == null) { @@ -355,9 +295,8 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill // it if possible. - // TODO: Move to TaskRecord after unification is done. - if (mTaskRecord != null && mTaskRecord.getParent() != null) { - mTaskRecord.onConfigurationChanged(mTaskRecord.getParent().getConfiguration()); + if (getParent() != null) { + onConfigurationChanged(getParent().getConfiguration()); return true; } return false; @@ -379,8 +318,9 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta } /** - * Sets bounds that override where the task is displayed. Used during transient operations - * like animation / interaction. + * Displayed bounds are used to set where the task is drawn at any given time. This is + * separate from its actual bounds so that the app doesn't see any meaningful configuration + * changes during transitionary periods. */ void setOverrideDisplayedBounds(Rect overrideDisplayedBounds) { if (overrideDisplayedBounds != null) { @@ -399,13 +339,13 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta return mOverrideDisplayedBounds; } - void setResizeable(int resizeMode) { - mResizeMode = resizeMode; + boolean isResizeable(boolean checkSupportsPip) { + return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode) + || (checkSupportsPip && mSupportsPictureInPicture)); } boolean isResizeable() { - return ActivityInfo.isResizeableMode(mResizeMode) || mSupportsPictureInPicture - || mWmService.mAtmService.mForceResizableActivities; + return isResizeable(true /* checkSupportsPip */); } /** @@ -462,6 +402,10 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta } } + /** + * Gets the current overridden displayed bounds. These will be empty if the task is not + * currently overriding where it is displayed. + */ @Override public Rect getDisplayedBounds() { if (mOverrideDisplayedBounds.isEmpty()) { @@ -577,7 +521,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER); } - private void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) { + void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) { if (displayContent == null) { return; } @@ -618,9 +562,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta displayContent.rotateBounds(mRotation, newRotation, mTmpRect2); if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) { - if (mTaskRecord != null) { - mTaskRecord.requestResize(getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION); - } + mAtmService.resizeTask(mTaskId, getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION); } } @@ -758,7 +700,8 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta } void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) { - mTaskRecord.onSnapshotChanged(snapshot); + mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged( + mTaskId, snapshot); } TaskDescription getTaskDescription() { @@ -794,11 +737,6 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta mDimmer.dontAnimateExit(); } - @Override - public String toString() { - return "{taskId=" + mTaskId + " appTokens=" + mChildren + "}"; - } - String getName() { return toShortString(); } @@ -825,9 +763,8 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta } } - @CallSuper - @Override - public void writeToProto(ProtoOutputStream proto, long fieldId, + // TODO(proto-merge): Remove once protos for TaskRecord and Task are merged. + void writeToProtoInnerTaskOnly(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { return; @@ -843,8 +780,10 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta proto.write(FILLS_PARENT, matchParentBounds()); getBounds().writeToProto(proto, BOUNDS); mOverrideDisplayedBounds.writeToProto(proto, DISPLAYED_BOUNDS); - proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth()); - proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight()); + if (mSurfaceControl != null) { + proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth()); + proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight()); + } proto.end(token); } diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index 6920d9d3a770..672827fbb5ee 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -52,11 +52,10 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; import static android.view.Display.DEFAULT_DISPLAY; -import static com.android.server.EventLogTags.WM_TASK_CREATED; +import static com.android.server.EventLogTags.WM_TASK_REMOVED; import static com.android.server.am.TaskRecordProto.ACTIVITIES; import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE; import static com.android.server.am.TaskRecordProto.BOUNDS; -import static com.android.server.am.TaskRecordProto.CONFIGURATION_CONTAINER; import static com.android.server.am.TaskRecordProto.FULLSCREEN; import static com.android.server.am.TaskRecordProto.ID; import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS; @@ -66,11 +65,9 @@ import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY; import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY; import static com.android.server.am.TaskRecordProto.RESIZE_MODE; import static com.android.server.am.TaskRecordProto.STACK_ID; +import static com.android.server.am.TaskRecordProto.TASK; import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS; @@ -85,10 +82,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; -import static com.android.server.wm.WindowContainer.POSITION_TOP; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static java.lang.Integer.MAX_VALUE; @@ -143,7 +136,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; -class TaskRecord extends ConfigurationContainer { +class TaskRecord extends Task { private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_ATM; private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; @@ -212,7 +205,6 @@ class TaskRecord extends ConfigurationContainer { */ private static TaskRecordFactory sTaskRecordFactory; - final int mTaskId; // Unique identifier for this task. String affinity; // The affinity name for this task, or null; may change identity. String rootAffinity; // Initial base affinity, or null; does not change from initial root. final IVoiceInteractionSession voiceSession; // Voice interaction session driving task @@ -238,17 +230,11 @@ class TaskRecord extends ConfigurationContainer { boolean hasBeenVisible; // Set if any activities in the task have been visible to the user. String stringName; // caching of toString() result. - int mUserId; // user for which this task was created boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity // was changed. int numFullscreen; // Number of fullscreen activities. - int mResizeMode; // The resize mode of this task and its activities. - // Based on the {@link ActivityInfo#resizeMode} of the root activity. - private boolean mSupportsPictureInPicture; // Whether or not this task and its activities - // support PiP. Based on the {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag - // of the root activity. /** Can't be put in lockTask mode. */ final static int LOCK_TASK_AUTH_DONT_LOCK = 0; /** Can enter app pinning with user approval. Can never start over existing lockTask task. */ @@ -264,13 +250,6 @@ class TaskRecord extends ConfigurationContainer { int mLockTaskUid = -1; // The uid of the application that called startLockTask(). - // This represents the last resolved activity values for this task - // NOTE: This value needs to be persisted with each task - TaskDescription mTaskDescription; - - /** List of all activities in the task arranged in history order */ - final ArrayList<ActivityRecord> mActivities; - /** Current stack. Setter must always be used to update the value. */ private ActivityStack mStack; @@ -308,8 +287,6 @@ class TaskRecord extends ConfigurationContainer { int mCallingUid; String mCallingPackage; - final ActivityTaskManagerService mAtmService; - private final Rect mTmpStableBounds = new Rect(); private final Rect mTmpNonDecorBounds = new Rect(); private final Rect mTmpBounds = new Rect(); @@ -328,17 +305,9 @@ class TaskRecord extends ConfigurationContainer { // This number will be assigned when we evaluate OOM scores for all visible tasks. int mLayerRank = -1; - // When non-empty, this represents the bounds this task will be drawn at. This gets set during - // transient operations such as split-divider dragging and animations. - // TODO(b/119687367): This member is temporary. - final Rect mDisplayedBounds = new Rect(); - /** Helper object used for updating override configuration. */ private Configuration mTmpConfig = new Configuration(); - // TODO: remove after unification - Task mTask; - /** Used by fillTaskInfo */ final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport(); @@ -346,21 +315,21 @@ class TaskRecord extends ConfigurationContainer { * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int, * ActivityInfo, Intent, TaskDescription)} instead. */ - TaskRecord(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, - Intent _intent, IVoiceInteractionSession _voiceSession, - IVoiceInteractor _voiceInteractor, TaskDescription _taskDescription) { + TaskRecord(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent, + IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, + TaskDescription _taskDescription, ActivityStack stack) { this(atmService, _taskId, _intent, null /*_affinityIntent*/, null /*_affinity*/, null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/, false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/, UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/, - null /*_lastDescription*/, new ArrayList<>(), System.currentTimeMillis(), + null /*_lastDescription*/, System.currentTimeMillis(), true /*neverRelinquishIdentity*/, _taskDescription != null ? _taskDescription : new TaskDescription(), _taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/, info.applicationInfo.uid, info.packageName, info.resizeMode, info.supportsPictureInPicture(), false /*_realActivitySuspended*/, false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info, - _voiceSession, _voiceInteractor); + _voiceSession, _voiceInteractor, stack); } /** Don't use constructor directly. This is only used by XML parser. */ @@ -368,15 +337,16 @@ class TaskRecord extends ConfigurationContainer { Intent _affinityIntent, String _affinity, String _rootAffinity, ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, - int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities, + int _effectiveUid, String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info, - IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) { - mAtmService = atmService; - mTaskId = _taskId; + IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, + ActivityStack stack) { + super(_taskId, stack != null ? stack.mTaskStack : null, _userId, resizeMode, + supportsPictureInPicture, _lastTaskDescription, atmService); mRemoteToken = new RemoteToken(this); affinityIntent = _affinityIntent; affinity = _affinity; @@ -390,15 +360,12 @@ class TaskRecord extends ConfigurationContainer { isAvailable = true; autoRemoveRecents = _autoRemoveRecents; askedCompatMode = _askedCompatMode; - mUserId = _userId; mUserSetupComplete = userSetupComplete; effectiveUid = _effectiveUid; touchActiveTime(); lastDescription = _lastDescription; - mActivities = activities; mLastTimeMoved = lastTimeMoved; mNeverRelinquishIdentity = neverRelinquishIdentity; - mTaskDescription = _lastTaskDescription; mAffiliatedTaskId = taskAffiliation; mAffiliatedTaskColor = taskAffiliationColor; mPrevAffiliateTaskId = prevTaskId; @@ -406,7 +373,6 @@ class TaskRecord extends ConfigurationContainer { mCallingUid = callingUid; mCallingPackage = callingPackage; mResizeMode = resizeMode; - mSupportsPictureInPicture = supportsPictureInPicture; if (info != null) { setIntent(_intent, info); setMinDimensions(info); @@ -418,39 +384,6 @@ class TaskRecord extends ConfigurationContainer { mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity); } - Task getTask() { - return mTask; - } - - void createTask(boolean onTop, boolean showForAllUsers) { - if (mTask != null) { - throw new IllegalArgumentException("mTask=" + mTask - + " already created for task=" + this); - } - - final Rect bounds = updateOverrideConfigurationFromLaunchBounds(); - final TaskStack stack = getStack().getTaskStack(); - - if (stack == null) { - throw new IllegalArgumentException("TaskRecord: invalid stack=" + mStack); - } - EventLog.writeEvent(WM_TASK_CREATED, mTaskId, stack.mStackId); - mTask = new Task(mTaskId, stack, mUserId, mAtmService.mWindowManager, mResizeMode, - mSupportsPictureInPicture, mTaskDescription, this); - final int position = onTop ? POSITION_TOP : POSITION_BOTTOM; - - if (!mDisplayedBounds.isEmpty()) { - mTask.setOverrideDisplayedBounds(mDisplayedBounds); - } - // We only want to move the parents to the parents if we are creating this task at the - // top of its stack. - stack.addTask(mTask, position, showForAllUsers, onTop /* moveParents */); - } - - void setTask(Task task) { - mTask = task; - } - void cleanUpResourcesForDestroy() { if (hasChild()) { return; @@ -473,60 +406,33 @@ class TaskRecord extends ConfigurationContainer { mAtmService.mStackSupervisor.mRecentTasks.remove(this); } - removeWindowContainer(); + removeIfPossible(); } @VisibleForTesting - void removeWindowContainer() { + @Override + void removeIfPossible() { mAtmService.getLockTaskController().clearLockedTask(this); - if (mTask == null) { - if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + mTaskId); - return; - } - mTask.removeIfPossible(); - mTask = null; - if (!getWindowConfiguration().persistTaskBounds()) { - // Reset current bounds for task whose bounds shouldn't be persisted so it uses - // default configuration the next time it launches. - setBounds(null); - } + super.removeIfPossible(); mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId); } - void onSnapshotChanged(TaskSnapshot snapshot) { - mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(mTaskId, snapshot); - } - void setResizeMode(int resizeMode) { if (mResizeMode == resizeMode) { return; } mResizeMode = resizeMode; - mTask.setResizeable(resizeMode); mAtmService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities(); } - void setTaskDockedResizing(boolean resizing) { - if (mTask == null) { - Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + mTaskId + " not found."); - return; - } - mTask.setTaskDockedResizing(resizing); - } - - // TODO: Consolidate this with the resize() method below. - public void requestResize(Rect bounds, int resizeMode) { - mAtmService.resizeTask(mTaskId, bounds, resizeMode); - } - boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) { mAtmService.deferWindowLayout(); try { final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0; - if (mTask == null) { + if (getParent() == null) { // Task doesn't exist in window manager yet (e.g. was restored from recents). // All we can do for now is update the bounds so it can be used when the task is // added to window manager. @@ -577,7 +483,7 @@ class TaskRecord extends ConfigurationContainer { } } } - mTask.resize(kept, forced); + resize(kept, forced); saveLaunchingStateIfNeeded(); @@ -588,19 +494,6 @@ class TaskRecord extends ConfigurationContainer { } } - // TODO: Investigate combining with the resize() method above. - void resizeWindowContainer() { - mTask.resize(false /* relayout */, false /* forced */); - } - - void getWindowContainerBounds(Rect bounds) { - if (mTask != null) { - mTask.getBounds(bounds); - } else { - bounds.setEmpty(); - } - } - /** * Convenience method to reparent a task to the top or bottom position of the stack. */ @@ -708,32 +601,16 @@ class TaskRecord extends ConfigurationContainer { // Adjust the position for the new parent stack as needed. position = toStack.getAdjustedPositionForTask(this, position, null /* starting */); - // Must reparent first in window manager to avoid a situation where AM can delete the - // we are coming from in WM before we reparent because it became empty. - mTask.reparent(toStack.getTaskStack(), position, - moveStackMode == REPARENT_MOVE_STACK_TO_FRONT); - final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront)); - // Move the task - sourceStack.removeTask(this, reason, moveStackToFront - ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING); - toStack.addTask(this, position, false /* schedulePictureInPictureModeChange */, reason); + + reparent(toStack.getTaskStack(), position, moveStackToFront, reason); if (schedulePictureInPictureModeChange) { // Notify of picture-in-picture mode changes supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack); } - // TODO: Ensure that this is actually necessary here - // Notify the voice session if required - if (voiceSession != null) { - try { - voiceSession.taskStarted(intent, mTaskId); - } catch (RemoteException e) { - } - } - // If the task had focus before (or we're requested to move focus), move focus to the // new stack by moving the stack to the front. if (r != null) { @@ -809,14 +686,6 @@ class TaskRecord extends ConfigurationContainer { || targetWindowingMode == WINDOWING_MODE_FREEFORM; } - void cancelWindowTransition() { - if (mTask == null) { - Slog.w(TAG_WM, "cancelWindowTransition: taskId " + mTaskId + " not found."); - return; - } - mTask.cancelTaskWindowTransition(); - } - /** * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD! */ @@ -970,65 +839,103 @@ class TaskRecord extends ConfigurationContainer { return (T) mStack; } - /** - * Must be used for setting parent stack because it performs configuration updates. - * Must be called after adding task as a child to the stack. - */ - // TODO(task-unify): Remove or rework after task level unification. - void setStack(ActivityStack stack) { - if (stack != null && !stack.isInStackLocked(this)) { - throw new IllegalStateException("Task must be added as a Stack child first."); - } - final ActivityStack oldStack = mStack; - mStack = stack; + // TODO(stack-unify): Can be removed on stack unified. + void onParentChanged(ActivityStack newParent, ActivityStack oldParent) { + onParentChanged( + newParent != null ? newParent.mTaskStack : null, + oldParent != null ? oldParent.mTaskStack : null); + } + + @Override + void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { + final ActivityStack oldStack = (oldParent != null) + ? ((TaskStack) oldParent).mActivityStack : null; + final ActivityStack newStack = (newParent != null) + ? ((TaskStack) newParent).mActivityStack : null; + + mStack = newStack; - // If the new {@link TaskRecord} is from a different {@link ActivityStack}, remove this - // {@link ActivityRecord} from its current {@link ActivityStack}. + super.onParentChanged(newParent, oldParent); - if (oldStack != mStack) { + if (oldStack != null) { for (int i = getChildCount() - 1; i >= 0; --i) { final ActivityRecord activity = getChildAt(i); + oldStack.onActivityRemovedFromStack(activity); + } - if (oldStack != null) { - oldStack.onActivityRemovedFromStack(activity); - } + updateTaskMovement(true /*toFront*/); - if (mStack != null) { - stack.onActivityAddedToStack(activity); + if (oldStack.inPinnedWindowingMode() + && (newStack == null || !newStack.inPinnedWindowingMode())) { + // Notify if a task from the pinned stack is being removed + // (or moved depending on the mode). + mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned(); + } + } + + if (newStack != null) { + for (int i = getChildCount() - 1; i >= 0; --i) { + final ActivityRecord activity = getChildAt(i); + newStack.onActivityAddedToStack(activity); + } + + // TODO: Ensure that this is actually necessary here + // Notify the voice session if required + if (voiceSession != null) { + try { + voiceSession.taskStarted(intent, mTaskId); + } catch (RemoteException e) { } } } - onParentChanged(mStack, oldStack); - } + // First time we are adding the task to the system. + if (oldParent == null && newParent != null) { - /** - * @return Id of current stack, {@link INVALID_STACK_ID} if no stack is set. - */ - int getStackId() { - return mStack != null ? mStack.mStackId : INVALID_STACK_ID; - } + // TODO: Super random place to be doing this, but aligns with what used to be done + // before we unified Task level. Look into if this can be done in a better place. + updateOverrideConfigurationFromLaunchBounds(); + } - @Override - protected int getChildCount() { - return mActivities.size(); - } + // Task is being removed. + if (oldParent != null && newParent == null) { + cleanUpResourcesForDestroy(); + } - @Override - protected ActivityRecord getChildAt(int index) { - return mActivities.get(index); + + // Update task bounds if needed. + adjustBoundsForDisplayChangeIfNeeded(getDisplayContent()); + + if (getWindowConfiguration().windowsAreScaleable()) { + // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them + // while a resize is pending. + forceWindowsScaleable(true /* force */); + } else { + forceWindowsScaleable(false /* force */); + } + + mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay(); } - @Override - protected ConfigurationContainer getParent() { - return mStack; + /** TODO(task-merge): Consolidate into {@link TaskStack#onChildPositionChanged}. */ + void updateTaskMovement(boolean toFront) { + if (isPersistable) { + mLastTimeMoved = System.currentTimeMillis(); + // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most + // recently will be most negative, tasks sent to the bottom before that will be less + // negative. Similarly for recent tasks moved to the top which will be most positive. + if (!toFront) { + mLastTimeMoved *= -1; + } + } + mAtmService.mRootActivityContainer.invalidateTaskLayers(); } - @Override - protected void onParentChanged( - ConfigurationContainer newParent, ConfigurationContainer oldParent) { - super.onParentChanged(newParent, oldParent); - mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay(); + /** + * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set. + */ + int getStackId() { + return mStack != null ? mStack.mStackId : INVALID_STACK_ID; } // Close up recents linked list. @@ -1121,16 +1028,6 @@ class TaskRecord extends ConfigurationContainer { return null; } - boolean isVisible() { - for (int i = getChildCount() - 1; i >= 0; --i) { - final ActivityRecord r = getChildAt(i); - if (r.visible) { - return true; - } - } - return false; - } - /** * Return true if any activities in this task belongs to input uid. */ @@ -1210,15 +1107,10 @@ class TaskRecord extends ConfigurationContainer { * Reorder the history stack so that the passed activity is brought to the front. */ final void moveActivityToFrontLocked(ActivityRecord newTop) { - if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, - "Removing and adding activity " + newTop - + " to stack at top callers=" + Debug.getCallers(4)); - - mActivities.remove(newTop); - mActivities.add(newTop); + if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity " + + newTop + " to stack at top callers=" + Debug.getCallers(4)); - // Make sure window manager is aware of the position change. - mTask.positionChildAtTop(newTop); + positionChildAtTop(newTop); updateEffectiveIntent(); } @@ -1232,19 +1124,29 @@ class TaskRecord extends ConfigurationContainer { return getChildAt(0).getActivityType(); } - /** Called when a Task child is added from the Task.java side. */ - // TODO(task-unify): Just override addChild to do what is needed when someone calls to add a - // child. - void onChildAdded(ActivityRecord r, int index) { + @Override + void addChild(ActivityRecord r, int index) { + if (r.getParent() != null) { + // Shouldn't already have a parent since we are just adding to the task...Maybe you + // meant to use reparent? + throw new IllegalStateException( + "r=" + r + " parent=" + r.getParent() + " task=" + this); + } + + // If this task had any child before we added this one. + boolean hadChild = hasChild(); + + index = getAdjustedAddPosition(r, index); + super.addChild(r, index); + + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this); r.inHistory = true; - // Remove r first, and if it wasn't already in the list and it's fullscreen, count it. - if (!mActivities.remove(r) && r.occludesParent()) { - // Was not previously in list. + if (r.occludesParent()) { numFullscreen++; } // Only set this based on the first activity - if (!hasChild()) { + if (!hadChild) { if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) { // Normally non-standard activity type for the activity record will be set when the // object is created, however we delay setting the standard application type until @@ -1264,20 +1166,6 @@ class TaskRecord extends ConfigurationContainer { r.setActivityType(getActivityType()); } - final int size = getChildCount(); - - if (index == size && size > 0) { - final ActivityRecord top = getChildAt(size - 1); - if (top.mTaskOverlay) { - // Place below the task overlay activity since the overlay activity should always - // be on top. - index--; - } - } - - index = Math.min(size, index); - mActivities.add(index, r); - updateEffectiveIntent(); if (r.isPersistable()) { mAtmService.notifyTaskPersisterLocked(this, false); @@ -1288,31 +1176,23 @@ class TaskRecord extends ConfigurationContainer { mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay(); } - // TODO(task-unify): Merge onChildAdded method below into this since task will be a single - // object. void addChild(ActivityRecord r) { - if (r.getParent() != null) { - // Shouldn't already have a parent since we are just adding to the task... - throw new IllegalStateException( - "r=" + r + " parent=" + r.getParent() + " task=" + this); - } + addChild(r, Integer.MAX_VALUE /* add on top */); + } - ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this); - // This means the activity isn't attached to Task.java yet. Go ahead and do that. - // TODO(task-unify): Remove/call super once we unify task level. - if (mTask != null) { - mTask.addChild(r, Integer.MAX_VALUE /* add on top */); - } else { - onChildAdded(r, Integer.MAX_VALUE); - } + @Override + void removeChild(ActivityRecord r) { + removeChild(r, "removeChild"); } - /** Called when a Task child is removed from the Task.java side. */ - // TODO(task-unify): Just override removeChild to do what is needed when someone calls to remove - // a child. - void onChildRemoved(ActivityRecord r) { - if (mActivities.remove(r) && r.occludesParent()) { - // Was previously in list. + void removeChild(ActivityRecord r, String reason) { + if (!mChildren.contains(r)) { + Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this); + return; + } + + super.removeChild(r); + if (r.occludesParent()) { numFullscreen--; } if (r.isPersistable()) { @@ -1336,16 +1216,19 @@ class TaskRecord extends ConfigurationContainer { // When destroying a task, tell the supervisor to remove it so that any activity it // has can be cleaned up correctly. This is currently the only place where we remove // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays - // state into removeTask(), we just clear the task here before the other residual + // state into removeChild(), we just clear the task here before the other residual // work. - // TODO: If the callers to removeTask() changes such that we have multiple places - // where we are destroying the task, move this back into removeTask() + // TODO: If the callers to removeChild() changes such that we have multiple places + // where we are destroying the task, move this back into removeChild() mAtmService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false /* killProcess */, - !REMOVE_FROM_RECENTS, "onChildRemoved"); + !REMOVE_FROM_RECENTS, reason); } } else if (!mReuseTask) { // Remove entire task if it doesn't have any activity left and it isn't marked for reuse - mStack.removeTask(this, "onChildRemoved", REMOVE_TASK_MODE_DESTROYING); + mStack.removeChild(this, reason); + EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, + "removeChild: last r=" + r + " in t=" + this); + removeIfPossible(); } } @@ -1380,7 +1263,7 @@ class TaskRecord extends ConfigurationContainer { * Completely remove all activities associated with an existing * task starting at a specified index. */ - final void performClearTaskAtIndexLocked(int activityNdx, String reason) { + private void performClearTaskAtIndexLocked(int activityNdx, String reason) { int numActivities = getChildCount(); for ( ; activityNdx < numActivities; ++activityNdx) { final ActivityRecord r = getChildAt(activityNdx); @@ -1390,7 +1273,7 @@ class TaskRecord extends ConfigurationContainer { if (mStack == null) { // Task was restored from persistent storage. r.takeFromHistory(); - mActivities.remove(activityNdx); + removeChild(r); --activityNdx; --numActivities; } else if (r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason, @@ -1526,20 +1409,13 @@ class TaskRecord extends ConfigurationContainer { " mLockTaskAuth=" + lockTaskAuthToString()); } - private boolean isResizeable(boolean checkSupportsPip) { - return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode) - || (checkSupportsPip && mSupportsPictureInPicture)); - } - - boolean isResizeable() { - return isResizeable(true /* checkSupportsPip */); - } - @Override public boolean supportsSplitScreenWindowingMode() { // A task can not be docked even if it is considered resizeable because it only supports // picture-in-picture mode but has a non-resizeable resizeMode return super.supportsSplitScreenWindowingMode() + // TODO(task-group): Probably makes sense to move this and associated code into + // WindowContainer so it affects every node. && mAtmService.mSupportsSplitScreenMultiWindow && (mAtmService.mForceResizableActivities || (isResizeable(false /* checkSupportsPip */) @@ -1672,15 +1548,13 @@ class TaskRecord extends ConfigurationContainer { } topActivity = false; } - mTaskDescription = new TaskDescription(label, null, iconResource, iconFilename, - colorPrimary, colorBackground, statusBarColor, navigationBarColor, + final TaskDescription taskDescription = new TaskDescription(label, null, iconResource, + iconFilename, colorPrimary, colorBackground, statusBarColor, navigationBarColor, statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent); - if (mTask != null) { - mTask.setTaskDescription(mTaskDescription); - } + setTaskDescription(taskDescription); // Update the task affiliation color if we are the parent of the group if (mTaskId == mAffiliatedTaskId) { - mAffiliatedTaskColor = mTaskDescription.getPrimaryColor(); + mAffiliatedTaskColor = taskDescription.getPrimaryColor(); } } } @@ -1903,38 +1777,6 @@ class TaskRecord extends ConfigurationContainer { } /** - * Displayed bounds are used to set where the task is drawn at any given time. This is - * separate from its actual bounds so that the app doesn't see any meaningful configuration - * changes during transitionary periods. - */ - void setDisplayedBounds(Rect bounds) { - if (bounds == null) { - mDisplayedBounds.setEmpty(); - } else { - mDisplayedBounds.set(bounds); - } - if (mTask != null) { - mTask.setOverrideDisplayedBounds( - mDisplayedBounds.isEmpty() ? null : mDisplayedBounds); - } - } - - /** - * Gets the current overridden displayed bounds. These will be empty if the task is not - * currently overriding where it is displayed. - */ - Rect getDisplayedBounds() { - return mDisplayedBounds; - } - - /** - * @return {@code true} if this has overridden displayed bounds. - */ - boolean hasDisplayedBounds() { - return !mDisplayedBounds.isEmpty(); - } - - /** * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than * intersectBounds on a side, then the respective side will not be intersected. * @@ -2190,16 +2032,10 @@ class TaskRecord extends ConfigurationContainer { computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig); } - /** @see WindowContainer#handlesOrientationChangeFromDescendant */ - boolean handlesOrientationChangeFromDescendant() { - return mTask != null && mTask.getParent() != null - && mTask.getParent().handlesOrientationChangeFromDescendant(); - } - /** - * Compute bounds (letterbox or pillarbox) for {@link #WINDOWING_MODE_FULLSCREEN} when the - * parent doesn't handle the orientation change and the requested orientation is different from - * the parent. + * Compute bounds (letterbox or pillarbox) for + * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the + * orientation change and the requested orientation is different from the parent. */ void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity, @NonNull Rect parentBounds, int parentOrientation) { @@ -2345,7 +2181,7 @@ class TaskRecord extends ConfigurationContainer { info.realActivity = realActivity; info.numActivities = mReuseActivitiesReport.numActivities; info.lastActiveTime = lastActiveTime; - info.taskDescription = new ActivityManager.TaskDescription(mTaskDescription); + info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription()); info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode(); info.resizeMode = mResizeMode; info.configuration.setTo(getConfiguration()); @@ -2435,7 +2271,7 @@ class TaskRecord extends ConfigurationContainer { } pw.println(")"); } - pw.print(prefix); pw.print("Activities="); pw.println(mActivities); + pw.print(prefix); pw.print("Activities="); pw.println(mChildren); if (!askedCompatMode || !inRecents || !isAvailable) { pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode); pw.print(" inRecents="); pw.print(inRecents); @@ -2490,6 +2326,7 @@ class TaskRecord extends ConfigurationContainer { return toString(); } + @Override public void writeToProto(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { @@ -2497,13 +2334,13 @@ class TaskRecord extends ConfigurationContainer { } final long token = proto.start(fieldId); - super.writeToProto(proto, CONFIGURATION_CONTAINER, logLevel); + writeToProtoInnerTaskOnly(proto, TASK, logLevel); proto.write(ID, mTaskId); for (int i = getChildCount() - 1; i >= 0; i--) { - ActivityRecord activity = getChildAt(i); + final ActivityRecord activity = getChildAt(i); activity.writeToProto(proto, ACTIVITIES); } - proto.write(STACK_ID, mStack.mStackId); + proto.write(STACK_ID, getStackId()); if (mLastNonFullscreenBounds != null) { mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS); } @@ -2579,8 +2416,8 @@ class TaskRecord extends ConfigurationContainer { if (lastDescription != null) { out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); } - if (mTaskDescription != null) { - mTaskDescription.saveToXml(out); + if (getTaskDescription() != null) { + getTaskDescription().saveToXml(out); } out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); @@ -2641,14 +2478,14 @@ class TaskRecord extends ConfigurationContainer { static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, - IVoiceInteractor voiceInteractor) { + IVoiceInteractor voiceInteractor, ActivityStack stack) { return getTaskRecordFactory().create( - service, taskId, info, intent, voiceSession, voiceInteractor); + service, taskId, info, intent, voiceSession, voiceInteractor, stack); } static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info, - Intent intent, TaskDescription taskDescription) { - return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription); + Intent intent, TaskDescription taskDescription, ActivityStack stack) { + return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription, stack); } static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) @@ -2665,15 +2502,15 @@ class TaskRecord extends ConfigurationContainer { TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, - IVoiceInteractor voiceInteractor) { + IVoiceInteractor voiceInteractor, ActivityStack stack) { return new TaskRecord(service, taskId, info, intent, voiceSession, voiceInteractor, - null /*taskDescription*/); + null /*taskDescription*/, stack); } TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info, - Intent intent, TaskDescription taskDescription) { + Intent intent, TaskDescription taskDescription, ActivityStack stack) { return new TaskRecord(service, taskId, info, intent, null /*voiceSession*/, - null /*voiceInteractor*/, taskDescription); + null /*voiceInteractor*/, taskDescription, stack); } /** @@ -2683,20 +2520,20 @@ class TaskRecord extends ConfigurationContainer { Intent affinityIntent, String affinity, String rootAffinity, ComponentName realActivity, ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents, boolean askedCompatMode, int userId, - int effectiveUid, String lastDescription, ArrayList<ActivityRecord> activities, + int effectiveUid, String lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity, TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended, - boolean userSetupComplete, int minWidth, int minHeight) { + boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) { return new TaskRecord(service, taskId, intent, affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents, - askedCompatMode, userId, effectiveUid, lastDescription, activities, + askedCompatMode, userId, effectiveUid, lastDescription, lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete, minWidth, minHeight, null /*ActivityInfo*/, null /*_voiceSession*/, - null /*_voiceInteractor*/); + null /*_voiceInteractor*/, stack); } TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) @@ -2908,15 +2745,15 @@ class TaskRecord extends ConfigurationContainer { taskId, intent, affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription, - activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription, + lastTimeOnTop, neverRelinquishIdentity, taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended, - userSetupComplete, minWidth, minHeight); + userSetupComplete, minWidth, minHeight, null /*stack*/); task.mLastNonFullscreenBounds = lastNonFullscreenBounds; task.setBounds(lastNonFullscreenBounds); for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { - activities.get(activityNdx).setTask(task); + task.addChild(activities.get(activityNdx)); } if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task); diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 56211e25f421..68b76fb14174 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -116,7 +116,6 @@ public class TaskStack extends WindowContainer<Task> implements /** ActivityRecords that are exiting, but still on screen for animations. */ final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>(); - final ArrayList<ActivityRecord> mTmpActivities = new ArrayList<>(); /** Detach this stack from its display when animation completes. */ // TODO: maybe tie this to WindowContainer#removeChild some how... @@ -330,7 +329,7 @@ public class TaskStack extends WindowContainer<Task> implements } /** Bounds of the stack with other system factors taken into consideration. */ - public void getDimBounds(Rect out) { + void getDimBounds(Rect out) { getBounds(out); } @@ -482,11 +481,6 @@ public class TaskStack extends WindowContainer<Task> implements dividerSize); } - // TODO: Checkout the call points of this method and the ones below to see how they can fit in WC. - void addTask(Task task, int position) { - addTask(task, position, task.showForAllUsers(), true /* moveParents */); - } - /** * Put a Task in this stack. Used for adding only. * When task is added to top of the stack, the entire branch of the hierarchy (including stack @@ -495,22 +489,21 @@ public class TaskStack extends WindowContainer<Task> implements * @param position Target position to add the task to. * @param showForAllUsers Whether to show the task regardless of the current user. */ - void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) { - final TaskStack currentStack = task.mStack; - // TODO: We pass stack to task's constructor, but we still need to call this method. - // This doesn't make sense, mStack will already be set equal to "this" at this point. - if (currentStack != null && currentStack.mStackId != mStackId) { - throw new IllegalStateException("Trying to add taskId=" + task.mTaskId - + " to stackId=" + mStackId - + ", but it is already attached to stackId=" + task.mStack.mStackId); - } - + void addChild(Task task, int position, boolean showForAllUsers, boolean moveParents) { // Add child task. task.mStack = this; addChild(task, null); // Move child to a proper position, as some restriction for position might apply. - positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers); + position = positionChildAt( + position, task, moveParents /* includingParents */, showForAllUsers); + // TODO(task-merge): Remove cast. + mActivityStack.onChildAdded((TaskRecord) task, position); + } + + @Override + void addChild(Task task, int position) { + addChild(task, position, task.showForAllUsers(), false /* includingParents */); } void positionChildAt(Task child, int position) { @@ -563,13 +556,12 @@ public class TaskStack extends WindowContainer<Task> implements /** * Overridden version of {@link TaskStack#positionChildAt(int, Task, boolean)}. Used in - * {@link TaskStack#addTask(Task, int, boolean showForAllUsers, boolean)}, as it can receive - * showForAllUsers param from {@link AppWindowToken} instead of {@link Task#showForAllUsers()}. + * {@link TaskStack#addChild(Task, int, boolean showForAllUsers, boolean)}, as it can receive + * showForAllUsers param from {@link ActivityRecord} instead of {@link Task#showForAllUsers()}. */ - private void positionChildAt(int position, Task child, boolean includingParents, + int positionChildAt(int position, Task child, boolean includingParents, boolean showForAllUsers) { - final int targetPosition = findPositionForTask(child, position, showForAllUsers, - false /* addingNew */); + final int targetPosition = findPositionForTask(child, position, showForAllUsers); super.positionChildAt(targetPosition, child, includingParents); // Log positioning. @@ -578,6 +570,14 @@ public class TaskStack extends WindowContainer<Task> implements final int toTop = targetPosition == mChildren.size() - 1 ? 1 : 0; EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop, targetPosition); + + return targetPosition; + } + + @Override + void onChildPositionChanged(WindowContainer child) { + // TODO(task-merge): Read comment on updateTaskMovement method. + //((TaskRecord) child).updateTaskMovement(true); } void reparent(int displayId, Rect outStackBounds, boolean onTop) { @@ -597,14 +597,13 @@ public class TaskStack extends WindowContainer<Task> implements // TODO: We should really have users as a window container in the hierarchy so that we don't // have to do complicated things like we are doing in this method. - private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers, - boolean addingNew) { + private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers) { final boolean canShowTask = showForAllUsers || mWmService.isCurrentProfileLocked(task.mUserId); final int stackSize = mChildren.size(); int minPosition = 0; - int maxPosition = addingNew ? stackSize : stackSize - 1; + int maxPosition = stackSize - 1; if (canShowTask) { minPosition = computeMinPosition(minPosition, stackSize); @@ -615,8 +614,7 @@ public class TaskStack extends WindowContainer<Task> implements // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid. if (targetPosition == POSITION_BOTTOM && minPosition == 0) { return POSITION_BOTTOM; - } else if (targetPosition == POSITION_TOP - && maxPosition == (addingNew ? stackSize : stackSize - 1)) { + } else if (targetPosition == POSITION_TOP && maxPosition == (stackSize - 1)) { return POSITION_TOP; } // Reset position based on minimum/maximum possible positions. @@ -669,24 +667,17 @@ public class TaskStack extends WindowContainer<Task> implements */ @Override void removeChild(Task task) { + if (!mChildren.contains(task)) { + // Not really in this stack anymore... + return; + } if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeChild: task=" + task); super.removeChild(task); task.mStack = null; - if (mDisplayContent != null) { - if (mChildren.isEmpty()) { - getParent().positionChildAt(POSITION_BOTTOM, this, false /* includingParents */); - } - mDisplayContent.setLayoutNeeded(); - } - for (int appNdx = mExitingActivities.size() - 1; appNdx >= 0; --appNdx) { - final ActivityRecord activity = mExitingActivities.get(appNdx); - if (activity.getTask() == task) { - activity.mIsExiting = false; - mExitingActivities.remove(appNdx); - } - } + // TODO(task-merge): Remove cast. + mActivityStack.onChildRemoved((TaskRecord) task, mDisplayContent); } @Override @@ -1298,7 +1289,7 @@ public class TaskStack extends WindowContainer<Task> implements super.writeToProto(proto, WINDOW_CONTAINER, logLevel); proto.write(ID, mStackId); for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) { - mChildren.get(taskNdx).writeToProto(proto, TASKS, logLevel); + mChildren.get(taskNdx).writeToProtoInnerTaskOnly(proto, TASKS, logLevel); } proto.write(FILLS_PARENT, matchParentBounds()); getRawBounds().writeToProto(proto, BOUNDS); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 7ce2b5eb727b..a393ba65fbc9 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -428,7 +428,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< parent.mTreeWeight += child.mTreeWeight; parent = parent.getParent(); } - onChildPositionChanged(); + onChildPositionChanged(child); } /** @@ -454,7 +454,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< parent.mTreeWeight -= child.mTreeWeight; parent = parent.getParent(); } - onChildPositionChanged(); + onChildPositionChanged(child); } /** @@ -583,7 +583,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (mChildren.peekLast() != child) { mChildren.remove(child); mChildren.add(child); - onChildPositionChanged(); + onChildPositionChanged(child); } if (includingParents && getParent() != null) { getParent().positionChildAt(POSITION_TOP, this /* child */, @@ -594,7 +594,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (mChildren.peekFirst() != child) { mChildren.remove(child); mChildren.addFirst(child); - onChildPositionChanged(); + onChildPositionChanged(child); } if (includingParents && getParent() != null) { getParent().positionChildAt(POSITION_BOTTOM, this /* child */, @@ -608,14 +608,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< // doing this adjustment here and remove any adjustments in the callers. mChildren.remove(child); mChildren.add(position, child); - onChildPositionChanged(); + onChildPositionChanged(child); } } /** * Notify that a child's position has changed. Possible changes are adding or removing a child. */ - void onChildPositionChanged() { } + void onChildPositionChanged(WindowContainer child) { } /** * Update override configuration and recalculate full config. diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 38d6c9c1e4db..2ce37f1be4c5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -53,8 +53,6 @@ import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityStack.ActivityState.STARTED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; @@ -136,13 +134,13 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testStackCleanupOnActivityRemoval() { - mTask.mTask.removeChild(mActivity); + mTask.removeChild(mActivity); verify(mStack, times(1)).onActivityRemovedFromStack(any()); } @Test public void testStackCleanupOnTaskRemoval() { - mStack.removeTask(mTask, null /*reason*/, REMOVE_TASK_MODE_MOVING); + mStack.removeChild(mTask, null /*reason*/); // Stack should be gone on task removal. assertNull(mService.mRootActivityContainer.getStack(mStack.mStackId)); } @@ -325,7 +323,7 @@ public class ActivityRecordTests extends ActivityTestsBase { : ORIENTATION_PORTRAIT; mTask.onRequestedOverrideConfigurationChanged(newConfig); - doReturn(true).when(mTask.mTask).isDragResizing(); + doReturn(true).when(mTask).isDragResizing(); mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; @@ -382,7 +380,7 @@ public class ActivityRecordTests extends ActivityTestsBase { } // Mimic the behavior that display doesn't handle app's requested orientation. - final DisplayContent dc = mTask.mTask.getDisplayContent(); + final DisplayContent dc = mTask.getDisplayContent(); doReturn(false).when(dc).onDescendantOrientationChanged(any(), any()); doReturn(false).when(dc).handlesOrientationChangeFromDescendant(); @@ -1174,7 +1172,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // Empty the home stack. final ActivityStack homeStack = mActivity.getDisplay().getHomeStack(); for (TaskRecord t : homeStack.getAllTasks()) { - homeStack.removeTask(t, "test", REMOVE_TASK_MODE_DESTROYING); + homeStack.removeChild(t, "test"); } mActivity.finishing = true; doReturn(false).when(mRootActivityContainer).resumeFocusedStacksTopActivities(); @@ -1200,7 +1198,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // Empty the home stack. final ActivityStack homeStack = mActivity.getDisplay().getHomeStack(); for (TaskRecord t : homeStack.getAllTasks()) { - homeStack.removeTask(t, "test", REMOVE_TASK_MODE_DESTROYING); + homeStack.removeChild(t, "test"); } mActivity.finishing = true; spyOn(mStack); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index fcebb81fd658..cc0cc3f85d50 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -38,7 +38,6 @@ import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; @@ -93,21 +92,6 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testEmptyTaskCleanupOnRemove() { - assertNotNull(mTask.getTask()); - mStack.removeTask(mTask, "testEmptyTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING); - assertNull(mTask.getTask()); - } - - @Test - public void testOccupiedTaskCleanupOnRemove() { - final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build(); - assertNotNull(mTask.getTask()); - mStack.removeTask(mTask, "testOccupiedTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING); - assertNotNull(mTask.getTask()); - } - - @Test public void testResumedActivity() { final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build(); assertNull(mStack.getResumedActivity()); @@ -996,27 +980,6 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testAdjustFocusedStackToHomeWhenNoActivity() { - final ActivityStack homeStask = mDefaultDisplay.getHomeStack(); - TaskRecord homeTask = homeStask.topTask(); - if (homeTask == null) { - // Create home task if there isn't one. - homeTask = new TaskBuilder(mSupervisor).setStack(homeStask).build(); - } - - final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); - mStack.moveToFront("testAdjustFocusedStack"); - - // Simulate that home activity has not been started or is force-stopped. - homeStask.removeTask(homeTask, "testAdjustFocusedStack", REMOVE_TASK_MODE_DESTROYING); - - // Finish the only activity. - topActivity.finishIfPossible("testAdjustFocusedStack", false /* oomAdj */); - // Although home stack is empty, it should still be the focused stack. - assertEquals(homeStask, mDefaultDisplay.getFocusedStack()); - } - - @Test public void testWontFinishHomeStackImmediately() { final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index ace5d4efa39b..a28bbb60d70c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -715,7 +715,7 @@ public class ActivityStarterTests extends ActivityTestsBase { if (startedActivity != null && startedActivity.getTaskRecord() != null) { // Remove the activity so it doesn't interfere with with subsequent activity launch // tests from this method. - startedActivity.getTaskRecord().mTask.removeChild(startedActivity); + startedActivity.getTaskRecord().removeChild(startedActivity); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 78db6c92772f..1db8f1b1b596 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -269,7 +269,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { // fullscreen value is normally read from resources in ctor, so for testing we need // to set it somewhere else since we can't mock resources. doReturn(true).when(activity).occludesParent(); - activity.setTask(mTaskRecord); + mTaskRecord.addChild(activity); // Make visible by default... activity.setHidden(false); } @@ -376,15 +376,13 @@ class ActivityTestsBase extends SystemServiceTestsBase { final TaskRecord task = new TaskRecord(mSupervisor.mService, mTaskId, aInfo, intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/, - null /*taskDescription*/); + null /*taskDescription*/, mStack); spyOn(task); task.mUserId = mUserId; if (mStack != null) { mStack.moveToFront("test"); - mStack.addTask(task, true, "creating test task"); - task.createTask(true, true); - spyOn(task.mTask); + mStack.addChild(task, true, true); } return task; diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java index 1fb6a563aa40..c5301b8a8c6e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java @@ -165,7 +165,7 @@ public class AppChangeTransitionTests extends WindowTestsBase { // setup currently defaults to no snapshot. setUpOnDisplay(mDisplayContent); - mTask.mTaskRecord.setWindowingMode(WINDOWING_MODE_FREEFORM); + mTask.setWindowingMode(WINDOWING_MODE_FREEFORM); assertEquals(1, mDisplayContent.mChangingApps.size()); assertTrue(mActivity.isInChangeTransition()); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index 2f0486d3e81b..d33dbd1dda7c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -48,7 +48,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import android.content.res.Configuration; @@ -63,7 +63,6 @@ import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; /** * Tests for the {@link ActivityRecord} class. @@ -209,9 +208,11 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test public void testSizeCompatBounds() { + // TODO(task-merge): Move once Task is merged into TaskRecord + final TaskRecord tr = (TaskRecord) mTask; // Disable the real configuration resolving because we only simulate partial flow. // TODO: Have test use full flow. - doNothing().when(mTask.mTaskRecord).computeConfigResourceOverrides(any(), any()); + doNothing().when(tr).computeConfigResourceOverrides(any(), any()); final Rect fixedBounds = mActivity.getRequestedOverrideConfiguration().windowConfiguration .getBounds(); fixedBounds.set(0, 0, 1200, 1600); @@ -337,11 +338,9 @@ public class AppWindowTokenTests extends WindowTestsBase { mDisplayContent.getDisplayRotation().setFixedToUserRotation( DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED); - - mTask.mTaskRecord = Mockito.mock(TaskRecord.class, RETURNS_DEEP_STUBS); + reset(mTask); mActivity.reportDescendantOrientationChangeIfNeeded(); - - verify(mTask.mTaskRecord).onConfigurationChanged(any(Configuration.class)); + verify(mTask).onConfigurationChanged(any(Configuration.class)); } @Test @@ -451,6 +450,7 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test public void testTransitionAnimationBounds() { + removeGlobalMinSizeRestriction(); final Rect stackBounds = new Rect(0, 0, 1000, 600); final Rect taskBounds = new Rect(100, 400, 600, 800); mStack.setBounds(stackBounds); @@ -458,16 +458,16 @@ public class AppWindowTokenTests extends WindowTestsBase { // Check that anim bounds for freeform window match task bounds mTask.setWindowingMode(WINDOWING_MODE_FREEFORM); - assertEquals(taskBounds, mActivity.getAnimationBounds(STACK_CLIP_NONE)); + assertEquals(mTask.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_NONE)); // STACK_CLIP_AFTER_ANIM should use task bounds since they will be clipped by // bounds animation layer. mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - assertEquals(taskBounds, mActivity.getAnimationBounds(STACK_CLIP_AFTER_ANIM)); + assertEquals(mTask.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_AFTER_ANIM)); // STACK_CLIP_BEFORE_ANIM should use stack bounds since it won't be clipped later. mTask.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - assertEquals(stackBounds, mActivity.getAnimationBounds(STACK_CLIP_BEFORE_ANIM)); + assertEquals(mStack.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_BEFORE_ANIM)); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index cc598ffa63bd..69091c61ec90 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -885,7 +885,7 @@ public class RecentTasksTest extends ActivityTestsBase { final int taskId = task.mTaskId; mRecentTasks.add(task); // Only keep the task in RecentTasks. - task.removeWindowContainer(); + task.removeIfPossible(); mStack.remove(); // The following APIs should not restore task from recents to the active list. diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java index 839ddb2038ff..ca8f5351c73a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java @@ -196,9 +196,6 @@ public class RecentsAnimationTest extends ActivityTestsBase { doReturn(app).when(mService).getProcessController(eq(recentActivity.processName), anyInt()); ClientLifecycleManager lifecycleManager = mService.getLifecycleManager(); doNothing().when(lifecycleManager).scheduleTransaction(any()); - AppWarnings appWarnings = mService.getAppWarningsLocked(); - spyOn(appWarnings); - doNothing().when(appWarnings).onStartActivity(any()); startRecentsActivity(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index aa97de72e507..63f70c05f203 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -36,7 +36,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityDisplay.POSITION_TOP; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; @@ -272,8 +271,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { assertTrue(pinnedActivity.isFocusable()); // Without the overridding activity, stack should not be focusable. - pinnedStack.removeTask(pinnedActivity.getTaskRecord(), "testFocusability", - REMOVE_TASK_MODE_DESTROYING); + pinnedStack.removeChild(pinnedActivity.getTaskRecord(), "testFocusability"); assertFalse(pinnedStack.isFocusable()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index fa1f435a37c0..ad1d1afe7603 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -437,6 +437,10 @@ public class SystemServicesTestRule implements TestRule { spyOn(getLockTaskController()); spyOn(getTaskChangeNotificationController()); initRootActivityContainerMocks(); + + AppWarnings appWarnings = getAppWarningsLocked(); + spyOn(appWarnings); + doNothing().when(appWarnings).onStartActivity(any()); } void initRootActivityContainerMocks() { diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java index df55b39b0817..012eb5252c50 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java @@ -79,8 +79,9 @@ public class TaskPositionerTests extends WindowTestsBase { // This should be the same calculation as the TaskPositioner uses. mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm); mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm); + removeGlobalMinSizeRestriction(); - mPositioner = new TaskPositioner(mWm, mock(IActivityTaskManager.class)); + mPositioner = new TaskPositioner(mWm, mWm.mAtmService); mPositioner.register(mDisplayContent); mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window"); @@ -493,10 +494,7 @@ public class TaskPositionerTests extends WindowTestsBase { + ") " + Log.getStackTraceString(new Throwable())); } } - assertEquals("left", expected.left, actual.left); - assertEquals("right", expected.right, actual.right); - assertEquals("top", expected.top, actual.top); - assertEquals("bottom", expected.bottom, actual.bottom); + assertEquals(expected, actual); } @FlakyTest(bugId = 129492888) diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java index f8d49ad18664..d2342f081fa1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java @@ -66,7 +66,8 @@ public class TaskPositioningControllerTests extends WindowTestsBase { any(InputChannel.class))).thenReturn(true); mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window"); - mWindow.getTask().setResizeable(RESIZE_MODE_RESIZEABLE); + // TODO(task-merge): Remove cast. + ((TaskRecord) mWindow.getTask()).setResizeMode(RESIZE_MODE_RESIZEABLE); mWindow.mInputChannel = new InputChannel(); mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow); doReturn(mock(InputMonitor.class)).when(mDisplayContent).getInputMonitor(); @@ -142,7 +143,8 @@ public class TaskPositioningControllerTests extends WindowTestsBase { doReturn(mWindow.getTask()).when(content).findTaskForResizePoint(anyInt(), anyInt()); assertNotNull(mWindow.getTask().getTopVisibleAppMainWindow()); - mWindow.getTask().setResizeable(RESIZE_MODE_UNRESIZEABLE); + // TODO(task-merge): Remove cast. + ((TaskRecord) mWindow.getTask()).setResizeMode(RESIZE_MODE_UNRESIZEABLE); mTarget.handleTapOutsideTask(content, 0, 0); // Wait until the looper processes finishTaskPositioning. diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java index a4e38f15e0e7..2cafc965e648 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java @@ -132,7 +132,7 @@ public class TaskRecordTests extends ActivityTestsBase { @Test public void testCopyBaseIntentForTaskInfo() { final TaskRecord task = createTaskRecord(1); - task.mTaskDescription = new ActivityManager.TaskDescription(); + task.setTaskDescription(new ActivityManager.TaskDescription()); final TaskInfo info = task.getTaskInfo(); // The intent of info should be a copy so assert that they are different instances. @@ -348,10 +348,12 @@ public class TaskRecordTests extends ActivityTestsBase { TaskRecord task = stack.getChildAt(0); ActivityRecord root = task.getTopActivity(); - final WindowContainer parentWindowContainer = mock(WindowContainer.class); - Mockito.doReturn(parentWindowContainer).when(task.mTask).getParent(); - Mockito.doReturn(true).when(parentWindowContainer) - .handlesOrientationChangeFromDescendant(); + final WindowContainer parentWindowContainer = + new WindowContainer(mSystemServicesTestRule.getWindowManagerService()); + spyOn(parentWindowContainer); + parentWindowContainer.setBounds(fullScreenBounds); + doReturn(parentWindowContainer).when(task).getParent(); + doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant(); // Setting app to fixed portrait fits within parent, but TaskRecord shouldn't adjust the // bounds because its parent says it will handle it at a later time. @@ -433,7 +435,7 @@ public class TaskRecordTests extends ActivityTestsBase { info.targetActivity = targetClassName; final TaskRecord task = TaskRecord.create(mService, 1 /* taskId */, info, intent, - null /* taskDescription */); + null /* taskDescription */, null /*stack*/); assertEquals("The alias activity component should be saved in task intent.", aliasClassName, task.intent.getComponent().getClassName()); @@ -834,8 +836,9 @@ public class TaskRecordTests extends ActivityTestsBase { private TaskRecord createTaskRecord(int taskId) { return new TaskRecord(mService, taskId, new Intent(), null, null, null, ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null, - new ArrayList<>(), 0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0, - 0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/); + 0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0, + 0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/, + null /*stack*/); } private static class TestTaskRecordFactory extends TaskRecordFactory { @@ -843,16 +846,16 @@ public class TaskRecordTests extends ActivityTestsBase { @Override TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info, - Intent intent, - IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) { + Intent intent, IVoiceInteractionSession voiceSession, + IVoiceInteractor voiceInteractor, ActivityStack stack) { mCreated = true; return null; } @Override TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info, - Intent intent, - ActivityManager.TaskDescription taskDescription) { + Intent intent, ActivityManager.TaskDescription taskDescription, + ActivityStack stack) { mCreated = true; return null; } @@ -863,14 +866,14 @@ public class TaskRecordTests extends ActivityTestsBase { ComponentName realActivity, ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents, boolean askedCompatMode, int userId, int effectiveUid, String lastDescription, - ArrayList<ActivityRecord> activities, long lastTimeMoved, + long lastTimeMoved, boolean neverRelinquishIdentity, ActivityManager.TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended, boolean userSetupComplete, int minWidth, - int minHeight) { + int minHeight, ActivityStack stack) { mCreated = true; return null; } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 4dfa26644fa9..cb2e1e03a446 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; @@ -92,7 +94,7 @@ public class TaskTests extends WindowTestsBase { boolean gotException = false; try { - task.reparent(stackController1, 0, false/* moveParents */); + task.reparent(stackController1, 0, false/* moveParents */, "testReparent"); } catch (IllegalArgumentException e) { gotException = true; } @@ -100,14 +102,14 @@ public class TaskTests extends WindowTestsBase { gotException = false; try { - task.reparent(null, 0, false/* moveParents */); + task.reparent(null, 0, false/* moveParents */, "testReparent"); } catch (IllegalArgumentException e) { gotException = true; } assertTrue("Should not be able to reparent to a stack that doesn't exist", gotException); - task.reparent(stackController2, 0, false/* moveParents */); + task.reparent(stackController2, 0, false/* moveParents */, "testReparent"); assertEquals(stackController2, task.getParent()); assertEquals(0, task.getParent().mChildren.indexOf(task)); assertEquals(1, task2.getParent().mChildren.indexOf(task2)); @@ -125,7 +127,7 @@ public class TaskTests extends WindowTestsBase { final TaskStack stack2 = createTaskStackOnDisplay(dc); final Task task2 = createTaskInStack(stack2, 0 /* userId */); // Reparent and check state - task.reparent(stack2, 0, false /* moveParents */); + task.reparent(stack2, 0, false /* moveParents */, "testReparent_BetweenDisplays"); assertEquals(stack2, task.getParent()); assertEquals(0, task.getParent().mChildren.indexOf(task)); assertEquals(1, task2.getParent().mChildren.indexOf(task2)); @@ -138,6 +140,7 @@ public class TaskTests extends WindowTestsBase { final Task task = createTaskInStack(stack1, 0 /* userId */); // Check that setting bounds also updates surface position + task.setWindowingMode(WINDOWING_MODE_FREEFORM); Rect bounds = new Rect(10, 10, 100, 200); task.setBounds(bounds); assertEquals(new Point(bounds.left, bounds.top), task.getLastSurfacePosition()); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java index 8cd97cb8a344..428d869fe3cd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java @@ -255,6 +255,7 @@ public class WindowFrameTests extends WindowTestsBase { @Test public void testLayoutNonfullscreenTask() { + removeGlobalMinSizeRestriction(); final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo(); final int logicalWidth = displayInfo.logicalWidth; final int logicalHeight = displayInfo.logicalHeight; @@ -264,8 +265,8 @@ public class WindowFrameTests extends WindowTestsBase { WindowState w = createWindow(); final Task task = w.getTask(); // Use split-screen because it is non-fullscreen, but also not floating - task.mTaskRecord.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); - task.mTaskRecord.setBounds(taskBounds); + task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + task.setBounds(taskBounds); // The bounds we are requesting might be different from what the system resolved based on // other factors. final Rect resolvedTaskBounds = task.getBounds(); @@ -303,8 +304,8 @@ public class WindowFrameTests extends WindowTestsBase { final int insetTop = logicalHeight / 5; final int insetRight = insetLeft + (resolvedTaskBounds.right - resolvedTaskBounds.left); final int insetBottom = insetTop + (resolvedTaskBounds.bottom - resolvedTaskBounds.top); - task.mTaskRecord.setDisplayedBounds(resolvedTaskBounds); - task.mTaskRecord.setBounds(insetLeft, insetTop, insetRight, insetBottom); + task.setOverrideDisplayedBounds(resolvedTaskBounds); + task.setBounds(insetLeft, insetTop, insetRight, insetBottom); windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect); w.computeFrameLw(); assertEquals(resolvedTaskBounds, w.getFrameLw()); @@ -477,7 +478,7 @@ public class WindowFrameTests extends WindowTestsBase { WindowState w = createWindow(); final Task task = w.getTask(); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; - task.mTaskRecord.setWindowingMode(WINDOWING_MODE_FREEFORM); + task.setWindowingMode(WINDOWING_MODE_FREEFORM); DisplayContent dc = mTestDisplayContent; dc.mInputMethodTarget = w; @@ -499,7 +500,7 @@ public class WindowFrameTests extends WindowTestsBase { // First check that it only gets moved up enough to show window. final Rect winRect = new Rect(200, 200, 300, 500); - task.mTaskRecord.setBounds(winRect); + task.setBounds(winRect); w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect); w.computeFrameLw(); @@ -511,7 +512,7 @@ public class WindowFrameTests extends WindowTestsBase { // Now check that it won't get moved beyond the top and then has appropriate insets winRect.bottom = 600; - task.mTaskRecord.setBounds(winRect); + task.setBounds(winRect); w.setBounds(winRect); w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect); w.computeFrameLw(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index 51daf6567a47..3f32e33a76ec 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -42,7 +42,7 @@ class WindowTestUtils { .setUserId(userId) .setStack(stack.mActivityStack) .build(); - return task.mTask; + return task; } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 780fed9805cb..c3f59eb75460 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -384,7 +384,7 @@ class WindowTestsBase extends SystemServiceTestsBase { } /** Sets the default minimum task size to 1 so that tests can use small task sizes */ - public void removeGlobalMinSizeRestriction() { + void removeGlobalMinSizeRestriction() { mWm.mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp = 1; } } |