From 28a72fbadbf7e0402afbfc05c08bf8212e8d1056 Mon Sep 17 00:00:00 2001 From: Louis Chang Date: Fri, 11 Jun 2021 20:43:16 +0800 Subject: [PATCH] Allowing leaf Task to contain both Activity and TaskFragment Allowing a leaf Task to both contains ActivityRecord and TaskFragment as the direct children. For example: Task - TaskFragment - Activity C - TaskFragment - Activity B - Activity A Bug: 189385903 Test: wm presubmit Change-Id: I79667df70dcbbefbf5a5cce1a24165247f403e69 --- data/etc/services.core.protolog.json | 12 +- .../com/android/server/wm/ActivityRecord.java | 8 +- .../wm/EnsureActivitiesVisibleHelper.java | 39 +++-- .../server/wm/RootWindowContainer.java | 2 +- .../core/java/com/android/server/wm/Task.java | 146 ++++++++++++------ .../android/server/wm/TaskDisplayArea.java | 33 ++-- .../com/android/server/wm/TaskFragment.java | 89 +++++++---- 7 files changed, 220 insertions(+), 109 deletions(-) diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 90137708e1796..178b751bfcf9f 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1627,6 +1627,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "-248761393": { + "message": "startPausing: taskFrag =%s mResumedActivity=%s", + "level": "DEBUG", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" + }, "-240296576": { "message": "handleAppTransitionReady: displayId=%d appTransition={%s} openingApps=[%s] closingApps=[%s] transit=%s", "level": "VERBOSE", @@ -3349,12 +3355,6 @@ "group": "WM_DEBUG_APP_TRANSITIONS", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "1814259538": { - "message": "pauseBackTasks: taskFrag=%s mResumedActivity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskDisplayArea.java" - }, "1822314934": { "message": "Expected target rootTask=%s to restored behind rootTask=%s but it is behind rootTask=%s", "level": "WARN", diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 7bd3565421467..df1e1af8d9427 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1182,7 +1182,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } } - pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label); + pw.print(prefix); pw.print(full ? "* " : " "); pw.print(label); pw.print(" #"); pw.print(index); pw.print(": "); pw.println(r); if (full) { @@ -3058,12 +3058,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Tell window manager to prepare for this one to be removed. setVisibility(false); - if (task.getTopPausingActivity() == null) { + if (getTaskFragment().getPausingActivity() == null) { ProtoLog.v(WM_DEBUG_STATES, "Finish needs to pause: %s", this); if (DEBUG_USER_LEAVING) { Slog.v(TAG_USER_LEAVING, "finish() => pause with userLeaving=false"); } - task.startPausing(false /* userLeaving */, false /* uiSleeping */, + getTaskFragment().startPausing(false /* userLeaving */, false /* uiSleeping */, null /* resuming */, "finish"); } @@ -5406,7 +5406,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (!task.hasChild(this)) { throw new IllegalStateException("Activity not found in its task"); } - return task.topRunningActivity() == this; + return getTaskFragment().topRunningActivity() == this; } void handleAlreadyVisible() { diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java index 027156f9ea941..2f0d703bb2000 100644 --- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java +++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java @@ -29,7 +29,7 @@ class EnsureActivitiesVisibleHelper { private ActivityRecord mStarting; private boolean mAboveTop; private boolean mContainerShouldBeVisible; - private boolean mBehindFullscreenActivity; + private boolean mBehindFullyOccludedContainer; private int mConfigChanges; private boolean mPreserveWindows; private boolean mNotifyClients; @@ -56,7 +56,7 @@ class EnsureActivitiesVisibleHelper { // are now visible. mAboveTop = mTop != null; mContainerShouldBeVisible = mTaskFragment.shouldBeVisible(mStarting); - mBehindFullscreenActivity = !mContainerShouldBeVisible; + mBehindFullyOccludedContainer = !mContainerShouldBeVisible; mConfigChanges = configChanges; mPreserveWindows = preserveWindows; mNotifyClients = notifyClients; @@ -97,9 +97,21 @@ class EnsureActivitiesVisibleHelper { && mTaskFragment.isTopActivityFocusable() && (starting == null || !starting.isDescendantOf(mTaskFragment)); - mTaskFragment.forAllActivities(a -> { - setActivityVisibilityState(a, starting, resumeTopActivity); - }); + for (int i = mTaskFragment.mChildren.size() - 1; i >= 0; --i) { + final WindowContainer child = mTaskFragment.mChildren.get(i); + if (child.asTaskFragment() != null) { + final TaskFragment childTaskFragment = child.asTaskFragment(); + childTaskFragment.updateActivityVisibilities(starting, configChanges, + preserveWindows, notifyClients); + mBehindFullyOccludedContainer = childTaskFragment.getBounds().equals( + mTaskFragment.getBounds()); + if (mAboveTop && mTop.getTaskFragment() == childTaskFragment) { + mAboveTop = false; + } + } else if (child.asActivityRecord() != null) { + setActivityVisibilityState(child.asActivityRecord(), starting, resumeTopActivity); + } + } if (mTaskFragment.mAtmService.getTransitionController().getTransitionPlayer() != null) { mTaskFragment.getDisplayContent().mWallpaperController.adjustWallpaperWindows(); } @@ -113,7 +125,7 @@ class EnsureActivitiesVisibleHelper { } mAboveTop = false; - r.updateVisibilityIgnoringKeyguard(mBehindFullscreenActivity); + r.updateVisibilityIgnoringKeyguard(mBehindFullyOccludedContainer); final boolean reallyVisible = r.shouldBeVisibleUnchecked(); // Check whether activity should be visible without Keyguard influence @@ -123,11 +135,11 @@ class EnsureActivitiesVisibleHelper { if (DEBUG_VISIBILITY) { Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r + " containerVisible=" + mContainerShouldBeVisible - + " behindFullscreen=" + mBehindFullscreenActivity); + + " behindFullyOccluded=" + mBehindFullyOccludedContainer); } - mBehindFullscreenActivity = true; + mBehindFullyOccludedContainer = true; } else { - mBehindFullscreenActivity = false; + mBehindFullyOccludedContainer = false; } } @@ -174,24 +186,25 @@ class EnsureActivitiesVisibleHelper { Slog.v(TAG_VISIBILITY, "Make invisible? " + r + " finishing=" + r.finishing + " state=" + r.getState() + " containerShouldBeVisible=" + mContainerShouldBeVisible - + " behindFullscreenActivity=" + mBehindFullscreenActivity + + " behindFullyOccludedContainer=" + mBehindFullyOccludedContainer + " mLaunchTaskBehind=" + r.mLaunchTaskBehind); } r.makeInvisible(); } - if (!mBehindFullscreenActivity && mTaskFragment.isActivityTypeHome() && r.isRootOfTask()) { + if (!mBehindFullyOccludedContainer && mTaskFragment.isActivityTypeHome() + && r.isRootOfTask()) { if (DEBUG_VISIBILITY) { Slog.v(TAG_VISIBILITY, "Home task: at " + mTaskFragment + " containerShouldBeVisible=" + mContainerShouldBeVisible - + " behindFullscreenActivity=" + mBehindFullscreenActivity); + + " behindOccludedParentContainer=" + mBehindFullyOccludedContainer); } // No other task in the root home task should be visible behind the home activity. // Home activities is usually a translucent activity with the wallpaper behind // them. However, when they don't have the wallpaper behind them, we want to // show activities in the next application root task behind them vs. another // task in the root home task like recents. - mBehindFullscreenActivity = true; + mBehindFullyOccludedContainer = true; } } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 4414db3bc2d01..6559746e725f1 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2377,7 +2377,7 @@ class RootWindowContainer extends WindowContainer if (displayShouldSleep) { rootTask.goToSleepIfPossible(false /* shuttingDown */); } else { - rootTask.forAllLeafTaskFragments( + rootTask.forAllLeafTasksAndLeafTaskFragments( taskFragment -> taskFragment.awakeFromSleeping(), true /* traverseTopToBottom */); if (rootTask.isFocusedRootTaskOnDisplay() diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index e7df2226a2bf5..e3e4c7089131f 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1258,22 +1258,35 @@ class Task extends TaskFragment { /** Returns the currently topmost resumed activity. */ @Nullable ActivityRecord getTopResumedActivity() { - if (isLeafTask()) { - final ActivityRecord[] resumedActivity = new ActivityRecord[1]; - forAllLeafTaskFragments(fragment -> { - if (fragment.getResumedActivity() != null) { - resumedActivity[0] = fragment.getResumedActivity(); - return true; + if (!isLeafTask()) { + for (int i = mChildren.size() - 1; i >= 0; --i) { + ActivityRecord resumedActivity = mChildren.get(i).asTask().getTopResumedActivity(); + if (resumedActivity != null) { + return resumedActivity; } - return false; - }); - return resumedActivity[0]; + } } + final ActivityRecord taskResumedActivity = getResumedActivity(); + ActivityRecord topResumedActivity = null; for (int i = mChildren.size() - 1; i >= 0; --i) { - ActivityRecord resumedActivity = mChildren.get(i).asTask().getTopResumedActivity(); - if (resumedActivity != null) { - return resumedActivity; + final WindowContainer child = mChildren.get(i); + if (child.asTaskFragment() != null) { + final ActivityRecord[] resumedActivity = new ActivityRecord[1]; + child.asTaskFragment().forAllLeafTaskFragments(fragment -> { + if (fragment.getResumedActivity() != null) { + resumedActivity[0] = fragment.getResumedActivity(); + return true; + } + return false; + }); + topResumedActivity = resumedActivity[0]; + } else if (taskResumedActivity != null + && child.asActivityRecord() == taskResumedActivity) { + topResumedActivity = taskResumedActivity; + } + if (topResumedActivity != null) { + return topResumedActivity; } } return null; @@ -1284,22 +1297,35 @@ class Task extends TaskFragment { */ @Nullable ActivityRecord getTopPausingActivity() { - if (isLeafTask()) { - final ActivityRecord[] pausingActivity = new ActivityRecord[1]; - forAllLeafTaskFragments(fragment -> { - if (fragment.getPausingActivity() != null) { - pausingActivity[0] = fragment.getPausingActivity(); - return true; + if (!isLeafTask()) { + for (int i = mChildren.size() - 1; i >= 0; --i) { + ActivityRecord pausingActivity = mChildren.get(i).asTask().getTopPausingActivity(); + if (pausingActivity != null) { + return pausingActivity; } - return false; - }); - return pausingActivity[0]; + } } + final ActivityRecord taskPausingActivity = getPausingActivity(); + ActivityRecord topPausingActivity = null; for (int i = mChildren.size() - 1; i >= 0; --i) { - ActivityRecord pausingActivity = mChildren.get(i).asTask().getTopPausingActivity(); - if (pausingActivity != null) { - return pausingActivity; + final WindowContainer child = mChildren.get(i); + if (child.asTaskFragment() != null) { + final ActivityRecord[] pausingActivity = new ActivityRecord[1]; + child.asTaskFragment().forAllLeafTaskFragments(fragment -> { + if (fragment.getPausingActivity() != null) { + pausingActivity[0] = fragment.getPausingActivity(); + return true; + } + return false; + }); + topPausingActivity = pausingActivity[0]; + } else if (taskPausingActivity != null + && child.asActivityRecord() == taskPausingActivity) { + topPausingActivity = taskPausingActivity; + } + if (topPausingActivity != null) { + return topPausingActivity; } } return null; @@ -1450,12 +1476,6 @@ class Task extends TaskFragment { @Override void addChild(WindowContainer child, int index) { - // If this task had any child before we added this one. - boolean hadChild = hasChild(); - // getActivityType() looks at the top child, so we need to read the type before adding - // a new child in case the new child is on top and UNDEFINED. - final int activityType = getActivityType(); - index = getAdjustedChildPosition(child, index); super.addChild(child, index); @@ -1470,11 +1490,11 @@ class Task extends TaskFragment { // Make sure the list of display UID allowlists is updated // now that this record is in a new task. mRootWindowContainer.updateUIDsPresentOnDisplay(); + } - final ActivityRecord r = child.asActivityRecord(); - if (r == null) return; - - r.inHistory = true; + /** Called when an {@link ActivityRecord} is added as a descendant */ + void onDescendantActivityAdded(boolean hadChild, int activityType, ActivityRecord r) { + warnForNonLeafTask("onDescendantActivityAdded"); // Only set this based on the first activity if (!hadChild) { @@ -1501,10 +1521,6 @@ class Task extends TaskFragment { updateEffectiveIntent(); } - void addChild(ActivityRecord r) { - addChild(r, Integer.MAX_VALUE /* add on top */); - } - @Override void removeChild(WindowContainer child) { removeChild(child, "removeChild"); @@ -3088,6 +3104,41 @@ class Task extends TaskFragment { return false; } + /** Iterates through all leaf task fragments and the leaf tasks. */ + void forAllLeafTasksAndLeafTaskFragments(final Consumer callback, + boolean traverseTopToBottom) { + forAllLeafTasks(task -> { + if (task.isLeafTaskFragment()) { + callback.accept(task); + return; + } + + // A leaf task that may contains both activities and task fragments. + boolean consumed = false; + if (traverseTopToBottom) { + for (int i = task.mChildren.size() - 1; i >= 0; --i) { + final WindowContainer child = mChildren.get(i); + if (child.asTaskFragment() != null) { + child.forAllLeafTaskFragments(callback, traverseTopToBottom); + } else if (child.asActivityRecord() != null && !consumed) { + callback.accept(task); + consumed = true; + } + } + } else { + for (int i = 0; i < task.mChildren.size(); i++) { + final WindowContainer child = mChildren.get(i); + if (child.asTaskFragment() != null) { + child.forAllLeafTaskFragments(callback, traverseTopToBottom); + } else if (child.asActivityRecord() != null && !consumed) { + callback.accept(task); + consumed = true; + } + } + } + }, traverseTopToBottom); + } + @Override boolean forAllRootTasks(Function callback, boolean traverseTopToBottom) { return isRootTask() ? callback.apply(this) : false; @@ -4618,11 +4669,11 @@ class Task extends TaskFragment { */ boolean goToSleepIfPossible(boolean shuttingDown) { final int[] sleepInProgress = {0}; - forAllLeafTaskFragments((f) -> { - if (!f.sleepIfPossible(shuttingDown)) { + forAllLeafTasksAndLeafTaskFragments(taskFragment -> { + if (!taskFragment.sleepIfPossible(shuttingDown)) { sleepInProgress[0]++; } - }, true); + }, true /* traverseTopToBottom */); return sleepInProgress[0] == 0; } @@ -4677,8 +4728,8 @@ class Task extends TaskFragment { boolean preserveWindows, boolean notifyClients) { mTaskSupervisor.beginActivityVisibilityUpdate(); try { - forAllLeafTaskFragments(fragment -> { - fragment.updateActivityVisibilities(starting, configChanges, preserveWindows, + forAllLeafTasks(task -> { + task.updateActivityVisibilities(starting, configChanges, preserveWindows, notifyClients); }, true /* traverseTopToBottom */); @@ -4845,13 +4896,20 @@ class Task extends TaskFragment { mRootWindowContainer.cancelInitializingActivities(); - if (topRunningActivity(true /* focusableOnly */) == null) { + final ActivityRecord topActivity = topRunningActivity(true /* focusableOnly */); + if (topActivity == null) { // There are no activities left in this task, let's look somewhere else. return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options); } final boolean[] resumed = new boolean[1]; + final TaskFragment topFragment = topActivity.getTaskFragment(); + resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause); forAllLeafTaskFragments(f -> { + if (topFragment == f) { + return; + } + resumed[0] |= f.resumeTopActivity(prev, options, deferPause); }, true); return resumed[0]; diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 5635adb909f6d..6fd2ddedbfbca 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -33,7 +33,6 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK; import static com.android.server.wm.DisplayContent.alwaysCreateRootTask; @@ -1451,18 +1450,30 @@ final class TaskDisplayArea extends DisplayArea { */ boolean pauseBackTasks(ActivityRecord resuming) { final int[] someActivityPaused = {0}; - forAllLeafTaskFragments((taskFragment) -> { - final ActivityRecord resumedActivity = taskFragment.getResumedActivity(); - if (resumedActivity != null - && (taskFragment.getVisibility(resuming) != TASK_FRAGMENT_VISIBILITY_VISIBLE - || !taskFragment.isTopActivityFocusable())) { - ProtoLog.d(WM_DEBUG_STATES, "pauseBackTasks: taskFrag=%s " - + "mResumedActivity=%s", taskFragment, resumedActivity); - if (taskFragment.startPausing(false /* uiSleeping*/, - resuming, "pauseBackTasks")) { - someActivityPaused[0]++; + forAllLeafTasks(leafTask -> { + // Check if the direct child resumed activity in the leaf task needed to be paused if + // the leaf task is not a leaf task fragment. + if (!leafTask.isLeafTaskFragment()) { + final ActivityRecord top = topRunningActivity(); + final ActivityRecord resumedActivity = leafTask.getResumedActivity(); + if (resumedActivity != null && top.getTaskFragment() != leafTask) { + // Pausing the resumed activity because it is occluded by other task fragment. + if (leafTask.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) { + someActivityPaused[0]++; + } } } + + leafTask.forAllLeafTaskFragments((taskFrag) -> { + final ActivityRecord resumedActivity = taskFrag.getResumedActivity(); + if (resumedActivity != null + && (taskFrag.getVisibility(resuming) != TASK_FRAGMENT_VISIBILITY_VISIBLE + || !taskFrag.isTopActivityFocusable())) { + if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) { + someActivityPaused[0]++; + } + } + }, true /* traverseTopToBottom */); }, true /* traverseTopToBottom */); return someActivityPaused[0] > 0; } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 0d71159f297bd..fe853fa93fee0 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -583,11 +583,10 @@ class TaskFragment extends WindowContainer { final int windowingMode = getWindowingMode(); final boolean isAssistantType = isActivityTypeAssistant(); for (int i = parent.getChildCount() - 1; i >= 0; --i) { - final WindowContainer wc = parent.getChildAt(i); - final TaskFragment other = wc.asTaskFragment(); + final WindowContainer other = parent.getChildAt(i); if (other == null) continue; - final boolean hasRunningActivities = other.topRunningActivity() != null; + final boolean hasRunningActivities = hasRunningActivity(other); if (other == this) { // Should be visible if there is no other fragment occluding it, unless it doesn't // have any running activities, not starting one and not home stack. @@ -603,7 +602,7 @@ class TaskFragment extends WindowContainer { final int otherWindowingMode = other.getWindowingMode(); if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) { - if (other.isTranslucent(starting)) { + if (isTranslucent(other, starting)) { // Can be visible behind a translucent fullscreen TaskFragment. gotTranslucentFullscreen = true; continue; @@ -611,7 +610,7 @@ class TaskFragment extends WindowContainer { return TASK_FRAGMENT_VISIBILITY_INVISIBLE; } else if (otherWindowingMode == WINDOWING_MODE_MULTI_WINDOW && other.matchParentBounds()) { - if (other.isTranslucent(starting)) { + if (isTranslucent(other, starting)) { // Can be visible behind a translucent TaskFragment. gotTranslucentFullscreen = true; continue; @@ -621,7 +620,7 @@ class TaskFragment extends WindowContainer { } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !gotOpaqueSplitScreenPrimary) { gotRootSplitScreenFragment = true; - gotTranslucentSplitScreenPrimary = other.isTranslucent(starting); + gotTranslucentSplitScreenPrimary = isTranslucent(other, starting); gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary; if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && gotOpaqueSplitScreenPrimary) { @@ -631,7 +630,7 @@ class TaskFragment extends WindowContainer { } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY && !gotOpaqueSplitScreenSecondary) { gotRootSplitScreenFragment = true; - gotTranslucentSplitScreenSecondary = other.isTranslucent(starting); + gotTranslucentSplitScreenSecondary = isTranslucent(other, starting); gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary; if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY && gotOpaqueSplitScreenSecondary) { @@ -651,10 +650,11 @@ class TaskFragment extends WindowContainer { return TASK_FRAGMENT_VISIBILITY_INVISIBLE; } - if (other.mAdjacentTaskFragment != null) { - if (adjacentTaskFragments.contains(other.mAdjacentTaskFragment)) { - if (other.isTranslucent(starting) - || other.mAdjacentTaskFragment.isTranslucent(starting)) { + final TaskFragment otherTaskFrag = other.asTaskFragment(); + if (otherTaskFrag != null && otherTaskFrag.mAdjacentTaskFragment != null) { + if (adjacentTaskFragments.contains(otherTaskFrag.mAdjacentTaskFragment)) { + if (otherTaskFrag.isTranslucent(starting) + || otherTaskFrag.mAdjacentTaskFragment.isTranslucent(starting)) { // Can be visible behind a translucent adjacent TaskFragments. gotTranslucentFullscreen = true; continue; @@ -662,7 +662,7 @@ class TaskFragment extends WindowContainer { // Can not be visible behind adjacent TaskFragments. return TASK_FRAGMENT_VISIBILITY_INVISIBLE; } else { - adjacentTaskFragments.add(other); + adjacentTaskFragments.add(otherTaskFrag); } } @@ -706,14 +706,28 @@ class TaskFragment extends WindowContainer { : TASK_FRAGMENT_VISIBILITY_VISIBLE; } - private boolean isTopActivityLaunchedBehind() { - final ActivityRecord top = topRunningActivity(); - if (top != null && top.mLaunchTaskBehind) { - return true; + private static boolean hasRunningActivity(WindowContainer wc) { + if (wc.asTaskFragment() != null) { + return wc.asTaskFragment().topRunningActivity() != null; + } + return wc.asActivityRecord() != null && !wc.asActivityRecord().finishing; + } + + private static boolean isTranslucent(WindowContainer wc, ActivityRecord starting) { + if (wc.asTaskFragment() != null) { + return wc.asTaskFragment().isTranslucent(starting); + } else if (wc.asActivityRecord() != null) { + return !wc.asActivityRecord().occludesParent(); } return false; } + + private boolean isTopActivityLaunchedBehind() { + final ActivityRecord top = topRunningActivity(); + return top != null && top.mLaunchTaskBehind; + } + final void updateActivityVisibilities(@Nullable ActivityRecord starting, int configChanges, boolean preserveWindows, boolean notifyClients) { mTaskSupervisor.beginActivityVisibilityUpdate(); @@ -801,7 +815,7 @@ class TaskFragment extends WindowContainer { boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next); if (mResumedActivity != null) { ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Pausing %s", mResumedActivity); - pausing |= startPausingInner(mTaskSupervisor.mUserLeaving, false /* uiSleeping */, + pausing |= startPausing(mTaskSupervisor.mUserLeaving, false /* uiSleeping */, next, "resumeTopActivity"); } if (pausing) { @@ -1109,17 +1123,6 @@ class TaskFragment extends WindowContainer { return startPausing(mTaskSupervisor.mUserLeaving, uiSleeping, resuming, reason); } - final boolean startPausing(boolean userLeaving, boolean uiSleeping, - ActivityRecord resuming, String reason) { - final int[] pausing = {0}; - forAllLeafTaskFragments((f) -> { - if (f.startPausingInner(userLeaving, uiSleeping, resuming, reason)) { - pausing[0]++; - } - }, true /* traverseTopToBottom */); - return pausing[0] > 0; - } - /** * Start pausing the currently resumed activity. It is an error to call this if there * is already an activity being paused or there is no resumed activity. @@ -1134,12 +1137,15 @@ class TaskFragment extends WindowContainer { * @return Returns true if an activity now is in the PAUSING state, and we are waiting for * it to tell us when it is done. */ - private boolean startPausingInner(boolean userLeaving, boolean uiSleeping, - ActivityRecord resuming, String reason) { + boolean startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming, + String reason) { if (!hasDirectChildActivities()) { return false; } + ProtoLog.d(WM_DEBUG_STATES, "startPausing: taskFrag =%s " + "mResumedActivity=%s", this, + mResumedActivity); + if (mPausingActivity != null) { Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity + " state=" + mPausingActivity.getState()); @@ -1396,6 +1402,29 @@ class TaskFragment extends WindowContainer { return false; } + void addChild(ActivityRecord r) { + addChild(r, POSITION_TOP); + } + + @Override + void addChild(WindowContainer child, int index) { + boolean isAddingActivity = child.asActivityRecord() != null; + final Task task = isAddingActivity ? getTask() : null; + + // If this task had any child before we added this one. + boolean taskHadChild = task != null && task.hasChild(); + // getActivityType() looks at the top child, so we need to read the type before adding + // a new child in case the new child is on top and UNDEFINED. + final int activityType = task != null ? task.getActivityType() : ACTIVITY_TYPE_UNDEFINED; + + super.addChild(child, index); + + if (isAddingActivity && task != null) { + child.asActivityRecord().inHistory = true; + task.onDescendantActivityAdded(taskHadChild, activityType, child.asActivityRecord()); + } + } + void executeAppTransition(ActivityOptions options) { // No app transition applied to the task fragment. }