summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/window/flags/window_surfaces.aconfig12
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java61
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java47
3 files changed, 111 insertions, 9 deletions
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 8ff2e6aebdd0..d866b0e2f89e 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -106,3 +106,15 @@ flag {
is_exported: true
bug: "293949943"
}
+
+flag {
+ namespace: "window_surfaces"
+ name: "fix_hide_overlay_api"
+ description: "Application that calls setHideOverlayWindows() shouldn't hide its own windows, this flag gate the fix of this issue."
+ is_fixed_read_only: true
+ is_exported: true
+ bug: "359424300"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9d499e60737c..8f530a374261 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -326,7 +326,6 @@ import android.window.WindowContainerToken;
import android.window.WindowContextInfo;
import com.android.internal.R;
-import com.android.internal.util.ToBooleanFunction;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -343,6 +342,7 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.LatencyTracker;
+import com.android.internal.util.ToBooleanFunction;
import com.android.internal.view.WindowManagerPolicyThread;
import com.android.server.AnimationThread;
import com.android.server.DisplayThread;
@@ -388,7 +388,6 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
-import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
@@ -673,6 +672,14 @@ public class WindowManagerService extends IWindowManager.Stub
private ArrayList<WindowState> mHidingNonSystemOverlayWindows = new ArrayList<>();
/**
+ * A map that tracks uid/count of windows that cause non-system overlay windows to be hidden.
+ * The key is the window's uid and the value is the number of windows with that uid that are
+ * requesting hiding non-system overlay
+ */
+ private final ArrayMap<Integer, Integer> mHidingNonSystemOverlayWindowsCountPerUid =
+ new ArrayMap<>();
+
+ /**
* In some cases (e.g. when {@link R.bool.config_reverseDefaultRotation} has value
* {@value true}) we need to map some orientation to others. This {@link SparseIntArray}
* contains the relation between the source orientation and the one to use.
@@ -1808,7 +1815,7 @@ public class WindowManagerService extends IWindowManager.Stub
UserHandle.getUserId(win.getOwningUid()));
win.setHiddenWhileSuspended(suspended);
- final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
+ final boolean hideSystemAlertWindows = shouldHideNonSystemOverlayWindow(win);
win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
boolean imMayMove = true;
@@ -2032,6 +2039,22 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ private boolean shouldHideNonSystemOverlayWindow(WindowState win) {
+ if (!Flags.fixHideOverlayApi()) {
+ return !mHidingNonSystemOverlayWindows.isEmpty();
+ }
+
+ if (mHidingNonSystemOverlayWindows.isEmpty()) {
+ return false;
+ }
+
+ if (mHidingNonSystemOverlayWindowsCountPerUid.size() == 1
+ && mHidingNonSystemOverlayWindowsCountPerUid.containsKey(win.getOwningUid())) {
+ return false;
+ }
+ return true;
+ }
+
/**
* Set whether screen capture is disabled for all windows of a specific user from
* the device policy cache, or specific windows based on sensitive content protections.
@@ -8733,22 +8756,42 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
final boolean systemAlertWindowsHidden = !mHidingNonSystemOverlayWindows.isEmpty();
+ final int numUIDsRequestHidingPreUpdate = mHidingNonSystemOverlayWindowsCountPerUid.size();
if (surfaceShown && win.hideNonSystemOverlayWindowsWhenVisible()) {
if (!mHidingNonSystemOverlayWindows.contains(win)) {
mHidingNonSystemOverlayWindows.add(win);
+ int uid = win.getOwningUid();
+ int count = mHidingNonSystemOverlayWindowsCountPerUid.getOrDefault(uid, 0);
+ mHidingNonSystemOverlayWindowsCountPerUid.put(uid, count + 1);
}
} else {
mHidingNonSystemOverlayWindows.remove(win);
+ int uid = win.getOwningUid();
+ int count = mHidingNonSystemOverlayWindowsCountPerUid.getOrDefault(uid, 0);
+ if (count <= 1) {
+ mHidingNonSystemOverlayWindowsCountPerUid.remove(win.getOwningUid());
+ } else {
+ mHidingNonSystemOverlayWindowsCountPerUid.put(uid, count - 1);
+ }
}
-
final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
-
- if (systemAlertWindowsHidden == hideSystemAlertWindows) {
- return;
+ final int numUIDSRequestHidingPostUpdate = mHidingNonSystemOverlayWindowsCountPerUid.size();
+ if (Flags.fixHideOverlayApi()) {
+ if (numUIDSRequestHidingPostUpdate == numUIDsRequestHidingPreUpdate) {
+ return;
+ }
+ // The visibility of SAWs needs to be refreshed only when the number of uids that
+ // request hiding SAWs changes 0->1, 1->0, 1->2 or 2->1.
+ if (numUIDSRequestHidingPostUpdate != 1 && numUIDsRequestHidingPreUpdate != 1) {
+ return;
+ }
+ } else {
+ if (systemAlertWindowsHidden == hideSystemAlertWindows) {
+ return;
+ }
}
-
mRoot.forAllWindows((w) -> {
- w.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
+ w.setForceHideNonSystemOverlayWindowIfNeeded(shouldHideNonSystemOverlayWindow(w));
}, false /* traverseTopToBottom */);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 7bc2c477f144..1323d8a59cef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -37,6 +37,7 @@ import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
@@ -1471,6 +1472,52 @@ public class WindowManagerServiceTests extends WindowTestsBase {
}
@Test
+ @EnableFlags(Flags.FLAG_FIX_HIDE_OVERLAY_API)
+ public void testUpdateOverlayWindows_singleWindowRequestsHiding_doNotHideOverlayWithSameUid() {
+ WindowState overlayWindow = newWindowBuilder("overlay_window",
+ TYPE_APPLICATION_OVERLAY).build();
+ WindowState appWindow = newWindowBuilder("app_window", TYPE_APPLICATION).build();
+ makeWindowVisible(appWindow, overlayWindow);
+
+ int uid = 100000;
+ spyOn(appWindow);
+ spyOn(overlayWindow);
+ doReturn(true).when(appWindow).hideNonSystemOverlayWindowsWhenVisible();
+ doReturn(uid).when(appWindow).getOwningUid();
+ doReturn(uid).when(overlayWindow).getOwningUid();
+
+ mWm.updateNonSystemOverlayWindowsVisibilityIfNeeded(appWindow, true);
+
+ verify(overlayWindow).setForceHideNonSystemOverlayWindowIfNeeded(false);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_FIX_HIDE_OVERLAY_API)
+ public void testUpdateOverlayWindows_multipleWindowsRequestHiding_hideOverlaysWithAnyUids() {
+ WindowState overlayWindow = newWindowBuilder("overlay_window",
+ TYPE_APPLICATION_OVERLAY).build();
+ WindowState appWindow1 = newWindowBuilder("app_window_1", TYPE_APPLICATION).build();
+ WindowState appWindow2 = newWindowBuilder("app_window_2", TYPE_APPLICATION).build();
+ makeWindowVisible(appWindow1, appWindow2, overlayWindow);
+
+ int uid1 = 100000;
+ int uid2 = 100001;
+ spyOn(appWindow1);
+ spyOn(appWindow2);
+ spyOn(overlayWindow);
+ doReturn(true).when(appWindow1).hideNonSystemOverlayWindowsWhenVisible();
+ doReturn(true).when(appWindow2).hideNonSystemOverlayWindowsWhenVisible();
+ doReturn(uid1).when(appWindow1).getOwningUid();
+ doReturn(uid1).when(overlayWindow).getOwningUid();
+ doReturn(uid2).when(appWindow2).getOwningUid();
+
+ mWm.updateNonSystemOverlayWindowsVisibilityIfNeeded(appWindow1, true);
+ mWm.updateNonSystemOverlayWindowsVisibilityIfNeeded(appWindow2, true);
+
+ verify(overlayWindow).setForceHideNonSystemOverlayWindowIfNeeded(true);
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_REPARENT_WINDOW_TOKEN_API)
public void reparentWindowContextToDisplayArea_newDisplay_reparented() {
final WindowToken windowToken = createTestClientWindowToken(TYPE_NOTIFICATION_SHADE,