diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index fd73632632ff1..d1b6efd3e23a9 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2791,7 +2791,9 @@ public class ActivityManager { @UnsupportedAppUsage public boolean visible; // Index of the stack in the display's stack list, can be used for comparison of stack order + // TODO: Can be removed since no one is using it. @UnsupportedAppUsage + @Deprecated public int position; public WindowContainerToken stackToken; /** diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 7a5ff41b18d95..e137428f511c3 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2183,7 +2183,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean isInStackLocked() { final ActivityStack stack = getRootTask(); - return stack != null && stack.isInStackLocked(this) != null; + return stack != null && stack.isInTask(this) != null; } boolean isPersistable() { @@ -5588,7 +5588,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A static ActivityRecord isInStackLocked(IBinder token) { final ActivityRecord r = ActivityRecord.forTokenLocked(token); - return (r != null) ? r.getRootTask().isInStackLocked(r) : null; + return (r != null) ? r.getRootTask().isInTask(r) : null; } static ActivityStack getStackLocked(IBinder token) { diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 5968eede0a279..893a843960a64 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -259,11 +259,9 @@ class ActivityStack extends Task { private Rect mTmpRect = new Rect(); private Rect mTmpRect2 = new Rect(); - /** For Pinned stack controlling. */ - private Rect mTmpToBounds = new Rect(); - /** Detach this stack from its display when animation completes. */ // TODO: maybe tie this to WindowContainer#removeChild some how... + // TODO: This is no longer set. Okay to remove or was the set removed by accident? private boolean mDeferRemoval; // If this is true, we are in the bounds animating mode. The task will be down or upscaled to @@ -281,7 +279,6 @@ class ActivityStack extends Task { /** * For {@link #prepareSurfaces}. */ - private final Rect mTmpDimBoundsRect = new Rect(); private final Point mLastSurfaceSize = new Point(); private final AnimatingActivityRegistry mAnimatingActivityRegistry = @@ -290,9 +287,6 @@ class ActivityStack extends Task { /** Stores the override windowing-mode from before a transient mode change (eg. split) */ private int mRestoreOverrideWindowingMode = WINDOWING_MODE_UNDEFINED; - /** List for processing through a set of activities */ - private final ArrayList mTmpActivities = new ArrayList<>(); - private boolean mTopActivityOccludesKeyguard; private ActivityRecord mTopDismissingKeyguardActivity; @@ -605,9 +599,6 @@ class ActivityStack extends Task { final int prevWindowingMode = getWindowingMode(); final boolean prevIsAlwaysOnTop = isAlwaysOnTop(); final int prevRotation = getWindowConfiguration().getRotation(); - final int prevDensity = getConfiguration().densityDpi; - final int prevScreenW = getConfiguration().screenWidthDp; - final int prevScreenH = getConfiguration().screenHeightDp; final Rect newBounds = mTmpRect; // Initialize the new bounds by previous bounds as the input and output for calculating // override bounds in pinned (pip) or split-screen mode. @@ -920,70 +911,6 @@ class ActivityStack extends Task { return false; } - ActivityRecord topRunningActivity() { - return topRunningActivity(false /* focusableOnly */); - } - - ActivityRecord topRunningActivity(boolean focusableOnly) { - // Split into 2 to avoid object creation due to variable capture. - if (focusableOnly) { - return getActivity((r) -> r.canBeTopRunning() && r.isFocusable()); - } else { - return getActivity(ActivityRecord::canBeTopRunning); - } - } - - private ActivityRecord topRunningNonOverlayTaskActivity() { - return getActivity((r) -> (r.canBeTopRunning() && !r.isTaskOverlay())); - } - - ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) { - final PooledPredicate p = PooledLambda.obtainPredicate(ActivityStack::isTopRunningNonDelayed - , PooledLambda.__(ActivityRecord.class), notTop); - final ActivityRecord r = getActivity(p); - p.recycle(); - return r; - } - - private static boolean isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop) { - return !r.delayedResume && r != notTop && r.canBeTopRunning(); - } - - /** - * This is a simplified version of topRunningActivity that provides a number of - * optional skip-over modes. It is intended for use with the ActivityController hook only. - * - * @param token If non-null, any history records matching this token will be skipped. - * @param taskId If non-zero, we'll attempt to skip over records with the same task ID. - * - * @return Returns the HistoryRecord of the next activity on the stack. - */ - ActivityRecord topRunningActivity(IBinder token, int taskId) { - final PooledPredicate p = PooledLambda.obtainPredicate(ActivityStack::isTopRunning, - PooledLambda.__(ActivityRecord.class), taskId, token); - final ActivityRecord r = getActivity(p); - p.recycle(); - return r; - } - - private static boolean isTopRunning(ActivityRecord r, int taskId, IBinder notTop) { - return r.getTask().mTaskId != taskId && r.appToken != notTop && r.canBeTopRunning(); - } - - ActivityRecord isInStackLocked(ActivityRecord r) { - if (r == null) { - return null; - } - final Task task = r.getRootTask(); - if (task != null && r.isDescendantOf(task)) { - if (task != this) Slog.w(TAG, "Illegal state! task does not point to stack it is in. " - + "stack=" + this + " task=" + task + " r=" + r - + " callers=" + Debug.getCallers(15, "\n")); - return r; - } - return null; - } - /** @return true if the stack can only contain one task */ boolean isSingleTaskInstance() { final DisplayContent display = getDisplay(); @@ -1106,12 +1033,6 @@ class ActivityStack extends Task { return isTopActivityFocusable() && shouldBeVisible(null /* starting */); } - @Override - public boolean isAttached() { - final TaskDisplayArea taskDisplayArea = getDisplayArea(); - return taskDisplayArea != null && !taskDisplayArea.isRemoved(); - } - // TODO: Should each user have there own stacks? @Override void switchUser(int userId) { @@ -1462,140 +1383,6 @@ class ActivityStack extends Task { return display != null && this == display.getFocusedStack(); } - /** - * Returns true if the stack should be visible. - * - * @param starting The currently starting activity or null if there is none. - */ - @Override - boolean shouldBeVisible(ActivityRecord starting) { - return getVisibility(starting) != STACK_VISIBILITY_INVISIBLE; - } - - /** - * Returns true if the stack should be visible. - * - * @param starting The currently starting activity or null if there is none. - */ - @StackVisibility - int getVisibility(ActivityRecord starting) { - if (!isAttached() || isForceHidden()) { - return STACK_VISIBILITY_INVISIBLE; - } - - final TaskDisplayArea taskDisplayArea = getDisplayArea(); - boolean gotSplitScreenStack = false; - boolean gotOpaqueSplitScreenPrimary = false; - boolean gotOpaqueSplitScreenSecondary = false; - boolean gotTranslucentFullscreen = false; - boolean gotTranslucentSplitScreenPrimary = false; - boolean gotTranslucentSplitScreenSecondary = false; - boolean shouldBeVisible = true; - final int windowingMode = getWindowingMode(); - final boolean isAssistantType = isActivityTypeAssistant(); - for (int i = taskDisplayArea.getStackCount() - 1; i >= 0; --i) { - final ActivityStack other = taskDisplayArea.getStackAt(i); - final boolean hasRunningActivities = other.topRunningActivity() != null; - if (other == this) { - // Should be visible if there is no other stack occluding it, unless it doesn't - // have any running activities, not starting one and not home stack. - shouldBeVisible = hasRunningActivities || isInStackLocked(starting) != null - || isActivityTypeHome(); - break; - } - - if (!hasRunningActivities) { - continue; - } - - final int otherWindowingMode = other.getWindowingMode(); - - if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) { - // In this case the home stack isn't resizeable even though we are in split-screen - // mode. We still want the primary splitscreen stack to be visible as there will be - // a slight hint of it in the status bar area above the non-resizeable home - // activity. In addition, if the fullscreen assistant is over primary splitscreen - // stack, the stack should still be visible in the background as long as the recents - // animation is running. - final int activityType = other.getActivityType(); - if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - if (activityType == ACTIVITY_TYPE_HOME - || (activityType == ACTIVITY_TYPE_ASSISTANT - && mWmService.getRecentsAnimationController() != null)) { - break; - } - } - if (other.isTranslucent(starting)) { - // Can be visible behind a translucent fullscreen stack. - gotTranslucentFullscreen = true; - continue; - } - return STACK_VISIBILITY_INVISIBLE; - } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY - && !gotOpaqueSplitScreenPrimary) { - gotSplitScreenStack = true; - gotTranslucentSplitScreenPrimary = other.isTranslucent(starting); - gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary; - if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY - && gotOpaqueSplitScreenPrimary) { - // Can not be visible behind another opaque stack in split-screen-primary mode. - return STACK_VISIBILITY_INVISIBLE; - } - } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY - && !gotOpaqueSplitScreenSecondary) { - gotSplitScreenStack = true; - gotTranslucentSplitScreenSecondary = other.isTranslucent(starting); - gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary; - if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY - && gotOpaqueSplitScreenSecondary) { - // Can not be visible behind another opaque stack in split-screen-secondary mode. - return STACK_VISIBILITY_INVISIBLE; - } - } - if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) { - // Can not be visible if we are in split-screen windowing mode and both halves of - // the screen are opaque. - return STACK_VISIBILITY_INVISIBLE; - } - if (isAssistantType && gotSplitScreenStack) { - // Assistant stack can't be visible behind split-screen. In addition to this not - // making sense, it also works around an issue here we boost the z-order of the - // assistant window surfaces in window manager whenever it is visible. - return STACK_VISIBILITY_INVISIBLE; - } - } - - if (!shouldBeVisible) { - return STACK_VISIBILITY_INVISIBLE; - } - - // Handle cases when there can be a translucent split-screen stack on top. - switch (windowingMode) { - case WINDOWING_MODE_FULLSCREEN: - if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) { - // At least one of the split-screen stacks that covers this one is translucent. - return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; - } - break; - case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: - if (gotTranslucentSplitScreenPrimary) { - // Covered by translucent primary split-screen on top. - return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; - } - break; - case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: - if (gotTranslucentSplitScreenSecondary) { - // Covered by translucent secondary split-screen on top. - return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; - } - break; - } - - // Lastly - check if there is a translucent fullscreen stack on top. - return gotTranslucentFullscreen ? STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT - : STACK_VISIBILITY_VISIBLE; - } - /** * Make sure that all activities that need to be visible in the stack (that is, they * currently can be seen by the user) actually are and update their configuration. diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 409e6ff998748..736bc9f8bc227 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -4065,7 +4065,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return r != null && r.getRootTask() != null && r.inPinnedWindowingMode() - && r.getRootTask().isInStackLocked(r) != null; + && r.getRootTask().isInTask(r) != null; } @Override diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index 9b3010344fd39..09700c56deba3 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -1398,10 +1398,9 @@ class RecentTasks { return false; } - // Trim tasks that are in stacks that are behind the home stack + // Trim tasks that are behind the home task. final TaskDisplayArea taskDisplayArea = stack.getDisplayArea(); - return taskDisplayArea.getIndexOf(stack) < taskDisplayArea.getIndexOf( - taskDisplayArea.getRootHomeTask()); + return task.compareTo(taskDisplayArea.getRootHomeTask()) < 0; } /** Remove the tasks that user may not be able to return. */ diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 51053b2e71233..bded65141a3a7 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -302,7 +302,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // Prefer to use the original target activity instead of top activity because // we may have moved another task to top (starting 3p launcher). final ActivityRecord targetActivity = targetStack != null - ? targetStack.isInStackLocked(mLaunchedTargetActivity) + ? targetStack.isInTask(mLaunchedTargetActivity) : null; ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onAnimationFinished(): targetStack=%s targetActivity=%s " diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 6b9054bde8685..7bdd9c986c0e4 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2425,6 +2425,7 @@ class RootWindowContainer extends WindowContainer info.userId = stack.mCurrentUser; info.visible = stack.shouldBeVisible(null); // A stack might be not attached to a display. + // TODO: Can be removed since no one is using it. info.position = taskDisplayArea != null ? taskDisplayArea.getIndexOf(stack) : 0; info.configuration.setTo(stack.getConfiguration()); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 299b3bf172d73..8d21fa0357d4c 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -65,6 +65,9 @@ import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_ import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; +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; 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; @@ -2346,7 +2349,9 @@ class Task extends WindowContainer { int windowingMode = getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode(); if (getActivityType() == ACTIVITY_TYPE_HOME && windowingMode == WINDOWING_MODE_UNDEFINED) { - windowingMode = inSplitScreenWindowingMode() ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY + final int parentWindowingMode = newParentConfig.windowConfiguration.getWindowingMode(); + windowingMode = parentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY + ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY : WINDOWING_MODE_FULLSCREEN; getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode); } @@ -3138,6 +3143,52 @@ class Task extends WindowContainer { return activity != null ? activity.findMainWindow() : null; } + ActivityRecord topRunningActivity() { + return topRunningActivity(false /* focusableOnly */); + } + + ActivityRecord topRunningActivity(boolean focusableOnly) { + // Split into 2 to avoid object creation due to variable capture. + if (focusableOnly) { + return getActivity((r) -> r.canBeTopRunning() && r.isFocusable()); + } else { + return getActivity(ActivityRecord::canBeTopRunning); + } + } + + ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) { + final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunningNonDelayed + , PooledLambda.__(ActivityRecord.class), notTop); + final ActivityRecord r = getActivity(p); + p.recycle(); + return r; + } + + private static boolean isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop) { + return !r.delayedResume && r != notTop && r.canBeTopRunning(); + } + + /** + * This is a simplified version of topRunningActivity that provides a number of + * optional skip-over modes. It is intended for use with the ActivityController hook only. + * + * @param token If non-null, any history records matching this token will be skipped. + * @param taskId If non-zero, we'll attempt to skip over records with the same task ID. + * + * @return Returns the HistoryRecord of the next activity on the stack. + */ + ActivityRecord topRunningActivity(IBinder token, int taskId) { + final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunning, + PooledLambda.__(ActivityRecord.class), taskId, token); + final ActivityRecord r = getActivity(p); + p.recycle(); + return r; + } + + private static boolean isTopRunning(ActivityRecord r, int taskId, IBinder notTop) { + return r.getTask().mTaskId != taskId && r.appToken != notTop && r.canBeTopRunning(); + } + ActivityRecord getTopFullscreenActivity() { return getActivity((r) -> { final WindowState win = r.findMainWindow(); @@ -3440,9 +3491,169 @@ class Task extends WindowContainer { return this; } - // TODO(task-merge): Figure-out how this should work with hierarchy tasks. + /** + * Returns true if the task should be visible. + * + * @param starting The currently starting activity or null if there is none. + */ boolean shouldBeVisible(ActivityRecord starting) { - return true; + return getVisibility(starting) != STACK_VISIBILITY_INVISIBLE; + } + + /** + * Returns true if the task should be visible. + * + * @param starting The currently starting activity or null if there is none. + */ + @ActivityStack.StackVisibility + int getVisibility(ActivityRecord starting) { + if (!isAttached() || isForceHidden()) { + return STACK_VISIBILITY_INVISIBLE; + } + + boolean gotSplitScreenStack = false; + boolean gotOpaqueSplitScreenPrimary = false; + boolean gotOpaqueSplitScreenSecondary = false; + boolean gotTranslucentFullscreen = false; + boolean gotTranslucentSplitScreenPrimary = false; + boolean gotTranslucentSplitScreenSecondary = false; + boolean shouldBeVisible = true; + + // This stack is only considered visible if all its parent stacks are considered visible, + // so check the visibility of all ancestor stacks first. + final WindowContainer parent = getParent(); + if (parent.asTask() != null) { + final int parentVisibility = parent.asTask().getVisibility(starting); + if (parentVisibility == STACK_VISIBILITY_INVISIBLE) { + // Can't be visible if parent isn't visible + return STACK_VISIBILITY_INVISIBLE; + } else if (parentVisibility == STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) { + // Parent is behind a translucent container so the highest visibility this container + // can get is that. + gotTranslucentFullscreen = true; + } + } + + final int windowingMode = getWindowingMode(); + final boolean isAssistantType = isActivityTypeAssistant(); + for (int i = parent.getChildCount() - 1; i >= 0; --i) { + final WindowContainer wc = parent.getChildAt(i); + final Task other = wc.asTask(); + if (other == null) continue; + + final boolean hasRunningActivities = other.topRunningActivity() != null; + if (other == this) { + // Should be visible if there is no other stack occluding it, unless it doesn't + // have any running activities, not starting one and not home stack. + shouldBeVisible = hasRunningActivities || isInTask(starting) != null + || isActivityTypeHome(); + break; + } + + if (!hasRunningActivities) { + continue; + } + + final int otherWindowingMode = other.getWindowingMode(); + + if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) { + // In this case the home stack isn't resizeable even though we are in split-screen + // mode. We still want the primary splitscreen stack to be visible as there will be + // a slight hint of it in the status bar area above the non-resizeable home + // activity. In addition, if the fullscreen assistant is over primary splitscreen + // stack, the stack should still be visible in the background as long as the recents + // animation is running. + final int activityType = other.getActivityType(); + if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + if (activityType == ACTIVITY_TYPE_HOME + || (activityType == ACTIVITY_TYPE_ASSISTANT + && mWmService.getRecentsAnimationController() != null)) { + break; + } + } + if (other.isTranslucent(starting)) { + // Can be visible behind a translucent fullscreen stack. + gotTranslucentFullscreen = true; + continue; + } + return STACK_VISIBILITY_INVISIBLE; + } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY + && !gotOpaqueSplitScreenPrimary) { + gotSplitScreenStack = true; + gotTranslucentSplitScreenPrimary = other.isTranslucent(starting); + gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary; + if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY + && gotOpaqueSplitScreenPrimary) { + // Can not be visible behind another opaque stack in split-screen-primary mode. + return STACK_VISIBILITY_INVISIBLE; + } + } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY + && !gotOpaqueSplitScreenSecondary) { + gotSplitScreenStack = true; + gotTranslucentSplitScreenSecondary = other.isTranslucent(starting); + gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary; + if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY + && gotOpaqueSplitScreenSecondary) { + // Can not be visible behind another opaque stack in split-screen-secondary mode. + return STACK_VISIBILITY_INVISIBLE; + } + } + if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) { + // Can not be visible if we are in split-screen windowing mode and both halves of + // the screen are opaque. + return STACK_VISIBILITY_INVISIBLE; + } + if (isAssistantType && gotSplitScreenStack) { + // Assistant stack can't be visible behind split-screen. In addition to this not + // making sense, it also works around an issue here we boost the z-order of the + // assistant window surfaces in window manager whenever it is visible. + return STACK_VISIBILITY_INVISIBLE; + } + } + + if (!shouldBeVisible) { + return STACK_VISIBILITY_INVISIBLE; + } + + // Handle cases when there can be a translucent split-screen stack on top. + switch (windowingMode) { + case WINDOWING_MODE_FULLSCREEN: + if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) { + // At least one of the split-screen stacks that covers this one is translucent. + return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; + } + break; + case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: + if (gotTranslucentSplitScreenPrimary) { + // Covered by translucent primary split-screen on top. + return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; + } + break; + case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: + if (gotTranslucentSplitScreenSecondary) { + // Covered by translucent secondary split-screen on top. + return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; + } + break; + } + + // Lastly - check if there is a translucent fullscreen stack on top. + return gotTranslucentFullscreen ? STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT + : STACK_VISIBILITY_VISIBLE; + } + + ActivityRecord isInTask(ActivityRecord r) { + if (r == null) { + return null; + } + final Task task = r.getRootTask(); + if (task != null && r.isDescendantOf(task)) { + if (task != this) Slog.w(TAG, "Illegal state! task does not point to stack it is in. " + + "stack=" + this + " task=" + task + " r=" + r + + " callers=" + Debug.getCallers(15, "\n")); + return r; + } + return null; } void dump(PrintWriter pw, String prefix) { diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index d71e56106e180..cb9b332a9f353 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -184,6 +184,7 @@ final class TaskDisplayArea extends DisplayArea { return count > 0 ? getChildAt(count - 1) : null; } + // TODO: Figure-out a way to remove since it might be a source of confusion. int getIndexOf(ActivityStack stack) { return mChildren.indexOf(stack); } @@ -690,7 +691,7 @@ final class TaskDisplayArea extends DisplayArea { // the position internally, also update the logic here final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null ? getFocusedStack() : null; - final boolean wasContained = getIndexOf(stack) >= 0; + final boolean wasContained = mChildren.contains(stack); if (mDisplayContent.mSingleTaskInstance && getStackCount() == 1 && !wasContained) { throw new IllegalStateException( "positionStackAt: Can only have one task on display=" + this); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 00c84ecb9f1fd..83e7ad57e68d4 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3532,7 +3532,7 @@ class WindowState extends WindowContainer implements WindowManagerP mClient.insetsControlChanged(getInsetsState(), stateController.getControlsForDispatch(this)); } catch (RemoteException e) { - Slog.w(TAG, "Failed to deliver inset state change", e); + Slog.w(TAG, "Failed to deliver inset state change to w=" + this, e); } } 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 3bed05f383a8c..0a6d3f3641fe2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; @@ -44,6 +45,7 @@ import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; +import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG; import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT; import static com.android.server.wm.TaskDisplayArea.getStackAbove; import static com.android.server.wm.WindowContainer.POSITION_TOP; @@ -488,6 +490,55 @@ public class ActivityStackTests extends ActivityTestsBase { splitScreenSecondary2.getVisibility(null /* starting */)); } + @Test + public void testGetVisibility_MultiLevel() { + final ActivityStack homeStack = createStackForShouldBeVisibleTest( + mDefaultTaskDisplayArea, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, + true /* onTop */); + final ActivityStack splitPrimary = createStackForShouldBeVisibleTest( + mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, + ACTIVITY_TYPE_UNDEFINED, true /* onTop */); + final ActivityStack splitSecondary = createStackForShouldBeVisibleTest( + mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, + ACTIVITY_TYPE_UNDEFINED, true /* onTop */); + + doReturn(false).when(homeStack).isTranslucent(any()); + doReturn(false).when(splitPrimary).isTranslucent(any()); + doReturn(false).when(splitSecondary).isTranslucent(any()); + + + // Re-parent home to split secondary. + homeStack.reparent(splitSecondary, POSITION_TOP); + // Current tasks should be visible. + assertEquals(STACK_VISIBILITY_VISIBLE, splitPrimary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE, splitSecondary.getVisibility(null /* starting */)); + // Home task should still be visible even though it is a child of another visible task. + assertEquals(STACK_VISIBILITY_VISIBLE, homeStack.getVisibility(null /* starting */)); + + + // Add fullscreen translucent task that partially occludes split tasks + final ActivityStack translucentStack = createStandardStackForVisibilityTest( + WINDOWING_MODE_FULLSCREEN, true /* translucent */); + // Fullscreen translucent task should be visible + assertEquals(STACK_VISIBILITY_VISIBLE, translucentStack.getVisibility(null /* starting */)); + // Split tasks should be visible behind translucent + assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + splitPrimary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + splitSecondary.getVisibility(null /* starting */)); + // Home task should be visible behind translucent since its parent is visible behind + // translucent. + assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, + homeStack.getVisibility(null /* starting */)); + + + // Hide split-secondary + splitSecondary.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, true /* set */); + // Home split secondary and home task should be invisible. + assertEquals(STACK_VISIBILITY_INVISIBLE, splitSecondary.getVisibility(null /* starting */)); + assertEquals(STACK_VISIBILITY_INVISIBLE, homeStack.getVisibility(null /* starting */)); + } + @Test public void testGetVisibility_FullscreenBehindTranslucent() { final ActivityStack bottomStack =