Loading core/java/android/window/flags/window_surfaces.aconfig +12 −0 Original line number Diff line number Diff line Loading @@ -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 } } services/core/java/com/android/server/wm/WindowManagerService.java +52 −9 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -672,6 +671,14 @@ public class WindowManagerService extends IWindowManager.Stub /** List of window currently causing non-system overlay windows to be hidden. */ 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} Loading Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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(); 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 */); } Loading services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +47 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -1470,6 +1471,52 @@ public class WindowManagerServiceTests extends WindowTestsBase { eq(windowToken.token)); } @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() { Loading Loading
core/java/android/window/flags/window_surfaces.aconfig +12 −0 Original line number Diff line number Diff line Loading @@ -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 } }
services/core/java/com/android/server/wm/WindowManagerService.java +52 −9 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -672,6 +671,14 @@ public class WindowManagerService extends IWindowManager.Stub /** List of window currently causing non-system overlay windows to be hidden. */ 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} Loading Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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(); 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 */); } Loading
services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +47 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -1470,6 +1471,52 @@ public class WindowManagerServiceTests extends WindowTestsBase { eq(windowToken.token)); } @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() { Loading