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

Commit 04497c48 authored by susalin's avatar susalin Committed by Jean Chen
Browse files

feat(magnify_ime): Add Option to Magnify Navigation Bar and IME [1/2]

Users who use screen magnifier now have the option to magnify
their navigation bar and IME (e.g. keyboard). We implement this through
a new Secure Setting monitored through the WindowManagerService,
which can be toggled by a user in the Settings.

Bug: 342509709
Flag: com.android.server.accessibility.enable_magnification_magnify_nav_bar_and_ime
Test: manually Navigate to Settings > Accessibility > Magnification
and turn on Magnify Navigation Bar and Keyboards .
Test that the navigation bar and keyboard can be magnified
depending on the setting. Turn the setting off, and the nav bar
and keyboard should not be magnifiable.
Test: atest WindowStateTests
(cherry picked from https://android-review.googlesource.com/q/commit:f8e9a266df16ac2a1f6f5ac525d6b9a490ab94fb)

Change-Id: I5496bcd9b5c3cf94620eedc7c86d12f31e86889a
parent 934ee77b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -202,7 +202,7 @@ public abstract class WindowManagerInternal {

        /**
         * Called when the region where magnification operates changes. Note that this isn't the
         * entire screen. For example, IMEs are not magnified.
         * entire screen. For example, IMEs are not always magnified.
         *
         * @param magnificationRegion the current magnification region
         */
+38 −0
Original line number Diff line number Diff line
@@ -701,6 +701,9 @@ public class WindowManagerService extends IWindowManager.Stub
    boolean mBootAnimationStopped = false;
    long mBootWaitForWindowsStartTime = -1;

    // Cache whether to Magnify the Navigation Bar and IME.
    private boolean mMagnifyNavAndIme = false;

    /** Dump of the windows and app tokens at the time of the last ANR. Cleared after
     * LAST_ANR_LIFETIME_DURATION_MSECS */
    String mLastANRState;
@@ -819,6 +822,8 @@ public class WindowManagerService extends IWindowManager.Stub
                Settings.Secure.getUriFor(Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS);
        private final Uri mDisableSecureWindowsUri =
                Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS);
        private final Uri mMagnifyNavAndImeEnabledUri = Settings.Secure.getUriFor(
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME);
        private final Uri mPolicyControlUri =
                Settings.Global.getUriFor(Settings.Global.POLICY_CONTROL);
        private final Uri mForceDesktopModeOnExternalDisplaysUri = Settings.Global.getUriFor(
@@ -851,6 +856,10 @@ public class WindowManagerService extends IWindowManager.Stub
                    UserHandle.USER_ALL);
            resolver.registerContentObserver(mDisableSecureWindowsUri, false, this,
                    UserHandle.USER_ALL);
            if (com.android.server.accessibility.Flags.enableMagnificationMagnifyNavBarAndIme()) {
                resolver.registerContentObserver(mMagnifyNavAndImeEnabledUri, false, this,
                        UserHandle.USER_ALL);
            }
            resolver.registerContentObserver(mPolicyControlUri, false, this, UserHandle.USER_ALL);
            resolver.registerContentObserver(mForceDesktopModeOnExternalDisplaysUri, false, this,
                    UserHandle.USER_ALL);
@@ -907,6 +916,10 @@ public class WindowManagerService extends IWindowManager.Stub
                return;
            }

            if (mMagnifyNavAndImeEnabledUri.equals(uri)) {
                updateMagnifyNavAndIme();
            }

            if (mDevelopmentOverrideDesktopExperienceUri.equals(uri)) {
                updateDevelopmentOverrideDesktopExperience();
                return;
@@ -931,6 +944,7 @@ public class WindowManagerService extends IWindowManager.Stub
        void loadSettings() {
            updateMaximumObscuringOpacityForTouch();
            updateDisableSecureWindows();
            updateMagnifyNavAndIme();
        }

        void updateMaximumObscuringOpacityForTouch() {
@@ -1030,6 +1044,25 @@ public class WindowManagerService extends IWindowManager.Stub
                mRoot.refreshSecureSurfaceState();
            }
        }

        void updateMagnifyNavAndIme() {
            if (!com.android.server.accessibility.Flags.enableMagnificationMagnifyNavBarAndIme()) {
                mMagnifyNavAndIme = false;
                return;
            }

            boolean enabledMagnifyNavAndIme = Settings.Secure.getIntForUser(
                        mContext.getContentResolver(),
                        Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME,
                    0, mCurrentUserId) == 1;
            if (mMagnifyNavAndIme == enabledMagnifyNavAndIme) {
                return;
            }

            synchronized (mGlobalLock) {
                mMagnifyNavAndIme = enabledMagnifyNavAndIme;
            }
        }
    }

    PowerManager mPowerManager;
@@ -1466,6 +1499,11 @@ public class WindowManagerService extends IWindowManager.Stub
                new ConfigurationChangeSettingInternalImpl());
    }

    @VisibleForTesting
    boolean isMagnifyNavAndImeEnabled() {
        return mMagnifyNavAndIme;
    }

    DisplayAreaPolicy.Provider getDisplayAreaPolicyProvider() {
        return mDisplayAreaPolicyProvider;
    }
+5 −3
Original line number Diff line number Diff line
@@ -4963,15 +4963,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
    @Override
    boolean shouldMagnify() {
        if (mAttrs.type == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY
                || mAttrs.type == TYPE_INPUT_METHOD
                || mAttrs.type == TYPE_INPUT_METHOD_DIALOG
                || mAttrs.type == TYPE_MAGNIFICATION_OVERLAY
                || mAttrs.type == TYPE_NAVIGATION_BAR
                // It's tempting to wonder: Have we forgotten the rounded corners overlay?
                // worry not: it's a fake TYPE_NAVIGATION_BAR_PANEL
                || mAttrs.type == TYPE_NAVIGATION_BAR_PANEL) {
            return false;
        }
        if (mAttrs.type == TYPE_INPUT_METHOD
                || mAttrs.type == TYPE_INPUT_METHOD_DIALOG
                || mAttrs.type == TYPE_NAVIGATION_BAR) {
            return mWmService.isMagnifyNavAndImeEnabled();
        }
        if ((mAttrs.privateFlags & PRIVATE_FLAG_NOT_MAGNIFIABLE) != 0) {
            return false;
        }
+98 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
@@ -41,7 +42,11 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -276,6 +281,99 @@ public class WindowStateTests extends WindowTestsBase {
        assertFalse(window.isVisibleByPolicy());
    }

    @Test
    @DisableFlags(com.android.server.accessibility
            .Flags.FLAG_ENABLE_MAGNIFICATION_MAGNIFY_NAV_BAR_AND_IME)
    public void testMagnifyNavAndIme_flagOffAndSettingsEnabled_typeIsIme_shouldNotMagnify() {
        final ContentResolver cr = useFakeSettingsProvider();
        Settings.Secure.putInt(cr,
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME, 1);
        mWm.mSettingsObserver.onChange(false /* selfChange */,
                Settings.Secure.getUriFor(
                        Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME));
        final WindowState imeWindow = newWindowBuilder("imeWindow", TYPE_INPUT_METHOD).build();
        final WindowState imeDialogWindow =
                newWindowBuilder("imeDialogWindow", TYPE_INPUT_METHOD_DIALOG).build();
        final WindowState navWindow = newWindowBuilder("navWindow", TYPE_NAVIGATION_BAR).build();

        imeWindow.setHasSurface(true);
        imeDialogWindow.setHasSurface(true);
        navWindow.setHasSurface(true);

        assertFalse(mWm.isMagnifyNavAndImeEnabled());
        assertFalse(imeWindow.shouldMagnify());
        assertFalse(imeDialogWindow.shouldMagnify());
        assertFalse(navWindow.shouldMagnify());
    }

    @Test
    @EnableFlags(com.android.server.accessibility
            .Flags.FLAG_ENABLE_MAGNIFICATION_MAGNIFY_NAV_BAR_AND_IME)
    public void testMagnifyNavAndIme_flagOnAndSettingsDisabled_typeIsIme_shouldNotMagnify() {
        final ContentResolver cr = useFakeSettingsProvider();
        Settings.Secure.putInt(cr,
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME, 0);
        mWm.mSettingsObserver.onChange(false /* selfChange */,
                Settings.Secure.getUriFor(
                        Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME));
        final WindowState imeWindow = newWindowBuilder("imeWindow", TYPE_INPUT_METHOD).build();
        final WindowState imeDialogWindow =
                newWindowBuilder("imeDialogWindow", TYPE_INPUT_METHOD_DIALOG).build();
        final WindowState navWindow = newWindowBuilder("navWindow", TYPE_NAVIGATION_BAR).build();

        imeWindow.setHasSurface(true);
        imeDialogWindow.setHasSurface(true);
        navWindow.setHasSurface(true);

        assertFalse(mWm.isMagnifyNavAndImeEnabled());
        assertFalse(imeWindow.shouldMagnify());
        assertFalse(imeDialogWindow.shouldMagnify());
        assertFalse(navWindow.shouldMagnify());
    }

    @Test
    public void testMagnifyNavAndIme_typeIsMagnification_shouldNotMagnify() {
        final WindowState a11yMagWindow = newWindowBuilder("a11yMagWindow",
                TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY).build();
        final WindowState magWindow = newWindowBuilder("magWindow",
                TYPE_MAGNIFICATION_OVERLAY).build();
        final WindowState navPanelWindow = newWindowBuilder("navPanelWindow",
                TYPE_NAVIGATION_BAR_PANEL).build();

        a11yMagWindow.setHasSurface(true);
        magWindow.setHasSurface(true);
        navPanelWindow.setHasSurface(true);

        assertFalse(a11yMagWindow.shouldMagnify());
        assertFalse(magWindow.shouldMagnify());
        assertFalse(navPanelWindow.shouldMagnify());
    }

    @Test
    @EnableFlags(com.android.server.accessibility
            .Flags.FLAG_ENABLE_MAGNIFICATION_MAGNIFY_NAV_BAR_AND_IME)
    public void testMagnifyNavAndIme_flagOnAndSettingsEnabled_typeIsIme_shouldMagnify() {
        final ContentResolver cr = useFakeSettingsProvider();
        Settings.Secure.putInt(cr,
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME, 1);
        mWm.mSettingsObserver.onChange(false /* selfChange */,
                Settings.Secure.getUriFor(
                        Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME));
        final WindowState imeWindow = newWindowBuilder("imeWindow", TYPE_INPUT_METHOD).build();
        final WindowState imeDialogWindow =
                newWindowBuilder("imeDialogWindow", TYPE_INPUT_METHOD_DIALOG).build();
        final WindowState navWindow = newWindowBuilder("navWindow", TYPE_NAVIGATION_BAR).build();

        imeWindow.setHasSurface(true);
        imeDialogWindow.setHasSurface(true);
        navWindow.setHasSurface(true);

        assertTrue(mWm.isMagnifyNavAndImeEnabled());
        assertTrue(imeWindow.shouldMagnify());
        assertTrue(imeDialogWindow.shouldMagnify());
        assertTrue(navWindow.shouldMagnify());
    }

    @Test
    public void testCanBeImeLayeringTarget() {
        final WindowState appWindow = newWindowBuilder("appWindow", TYPE_APPLICATION).build();