Fixed Task#getVisibility to take into account task hierarchy
Also, correct some uses of getRootHomeTask()
Fixes: 153086746
Bug: 154331729
Bug: 80414790
Test: atest WmTests:ActivityStackTests#testGetVisibility_MultiLevel
Change-Id: I8b9a38879a0b4e6c72686312b414319b8b086cd1
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index fd73632..d1b6efd 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2791,7 +2791,9 @@
@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 521ffa5..1d8eec6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2176,7 +2176,7 @@
boolean isInStackLocked() {
final ActivityStack stack = getRootTask();
- return stack != null && stack.isInStackLocked(this) != null;
+ return stack != null && stack.isInTask(this) != null;
}
boolean isPersistable() {
@@ -5580,7 +5580,7 @@
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 5968eede..893a843 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 @@
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 @@
/**
* For {@link #prepareSurfaces}.
*/
- private final Rect mTmpDimBoundsRect = new Rect();
private final Point mLastSurfaceSize = new Point();
private final AnimatingActivityRegistry mAnimatingActivityRegistry =
@@ -290,9 +287,6 @@
/** 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<ActivityRecord> mTmpActivities = new ArrayList<>();
-
private boolean mTopActivityOccludesKeyguard;
private ActivityRecord mTopDismissingKeyguardActivity;
@@ -605,9 +599,6 @@
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 @@
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 @@
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) {
@@ -1463,140 +1384,6 @@
}
/**
- * 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 d92f43b..0b78a12 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 @@
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 9b30103..09700c5 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 @@
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 51053b2..bded651 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 @@
// 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 e8f7ba5..1f63e9d 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2422,6 +2422,7 @@
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 1ffa01c..b01ce72 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_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;
@@ -2344,7 +2347,9 @@
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);
}
@@ -3136,6 +3141,52 @@
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();
@@ -3436,9 +3487,169 @@
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 d71e561..cb9b332 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 @@
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 @@
// 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 2b1f174..1c5fd7e 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 @@
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 3bed05f..0a6d3f3 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 @@
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_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;
@@ -489,6 +491,55 @@
}
@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 =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,