Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 694a181b authored by Yi Jiang's avatar Yi Jiang
Browse files

Update WindowManagerService#setHideOverlayWindows

1) If there is only one application requesting hide overlay windows, its
   own overlay windows won't be hidden.
2) If there are more than one applications requesting hide overlay
   windows. All overlay windows will be hidden.

Test: cts
Bug: 359424300
Flag: com.android.window.flags.fix_hide_overlay_api
Change-Id: Id6ee1a910eca4b574e89e2ec14befc0fa6e2e375
parent 218dbd8e
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -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
    }
}
+52 −9
Original line number Diff line number Diff line
@@ -325,7 +325,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;
@@ -342,6 +341,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;
@@ -387,7 +387,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;
@@ -671,6 +670,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}
@@ -1807,7 +1814,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;
@@ -2025,6 +2032,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.
@@ -8709,22 +8732,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 */);
    }

+47 −0
Original line number Diff line number Diff line
@@ -36,6 +36,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;
@@ -1435,6 +1436,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() {