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

Commit 2e9eba8a authored by Hiroki Sato's avatar Hiroki Sato
Browse files

fix(magnify_ime): magnifies navBar when mouse or keyboard connected

Magnifying the nav bar is disabled in the previous commit [1].
This change adds back the magnification behavior of TYPE_NAVIGATION_BAR
but only when there's an active mouse or keyboard.

When a mouse or a keyboard is connected, we can expect that the user is
primarily using these devices to interact, instead of touch, thus,
- We don't need to keep showing 3 button bar at the same position of the
  screen.
- Instread, we want to magnify the entire screen to make sure all content
  user interacts, especially a task bar in large screen, are magnified.

[1] Icd42a530315717473cf93706aee625993821122e

Bug: 418892460
Test: WindowStateTests
Test: manually, connect / disconnect a mouse and a keyboard, toggle "magnify keyboard"
Flag: com.android.server.accessibility.enable_magnification_magnify_nav_bar_and_ime

Change-Id: I6db97a1f6e87a03359fcabb658b18932d3e899e1
parent 56f93335
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -5484,8 +5484,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
    }

    void reapplyMagnificationSpec() {
        reapplyMagnificationSpec(getPendingTransaction());
    }

    void reapplyMagnificationSpec(Transaction t) {
        if (mMagnificationSpec != null) {
            applyMagnificationSpec(getPendingTransaction(), mMagnificationSpec);
            applyMagnificationSpec(t, mMagnificationSpec);
        }
    }

+3 −0
Original line number Diff line number Diff line
@@ -146,6 +146,9 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
                mInputDevicesReadyMonitor.notifyAll();
            }
        }

        mService.onInputDevicesChanged();

        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }

+26 −1
Original line number Diff line number Diff line
@@ -700,6 +700,7 @@ public class WindowManagerService extends IWindowManager.Stub

    // Cache whether to Magnify the IME.
    private boolean mMagnifyIme = false;
    private boolean mIsMouseOrKeyboardConnected = false;

    /** Dump of the windows and app tokens at the time of the last ANR. Cleared after
     * LAST_ANR_LIFETIME_DURATION_MSECS */
@@ -1508,11 +1509,14 @@ public class WindowManagerService extends IWindowManager.Stub
                new ConfigurationChangeSettingInternalImpl());
    }

    @VisibleForTesting
    boolean isMagnifyImeEnabled() {
        return mMagnifyIme;
    }

    boolean isMagnifyNavBarEnabled() {
        return mMagnifyIme && mIsMouseOrKeyboardConnected;
    }

    DisplayAreaPolicy.Provider getDisplayAreaPolicyProvider() {
        return mDisplayAreaPolicyProvider;
    }
@@ -1564,6 +1568,27 @@ public class WindowManagerService extends IWindowManager.Stub
        return mInputManagerCallback;
    }

    void onInputDevicesChanged() {
        boolean hasMouseOrKeyboard = false;
        for (final InputDevice device : mInputManager.getInputDevices()) {
            if (!device.isEnabled() || device.isVirtual()) {
                continue;
            }
            if (device.supportsSource(InputDevice.SOURCE_MOUSE) || device.isFullKeyboard()) {
                hasMouseOrKeyboard = true;
                break;
            }
        }
        synchronized (mGlobalLock) {
            if (mIsMouseOrKeyboardConnected != hasMouseOrKeyboard) {
                mIsMouseOrKeyboardConnected = hasMouseOrKeyboard;
                var t = mTransactionFactory.get();
                mRoot.forAllDisplays(dc -> dc.reapplyMagnificationSpec(t));
                t.apply();
            }
        }
    }

    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
+3 −1
Original line number Diff line number Diff line
@@ -4935,7 +4935,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
    boolean shouldMagnify() {
        if (mAttrs.type == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY
                || 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) {
@@ -4945,6 +4944,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                || mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
            return mWmService.isMagnifyImeEnabled();
        }
        if (mAttrs.type == TYPE_NAVIGATION_BAR) {
            return mWmService.isMagnifyNavBarEnabled();
        }
        if ((mAttrs.privateFlags & PRIVATE_FLAG_NOT_MAGNIFIABLE) != 0) {
            return false;
        }
+99 −0
Original line number Diff line number Diff line
@@ -107,10 +107,12 @@ import android.util.ArraySet;
import android.util.MergedConfiguration;
import android.view.Gravity;
import android.view.IWindow;
import android.view.InputDevice;
import android.view.InputWindowHandle;
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.KeyCharacterMap;
import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowInsets;
@@ -130,6 +132,7 @@ import com.android.server.wm.SensitiveContentPackages.PackageInfo;
import com.android.window.flags.Flags;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@@ -150,6 +153,14 @@ import java.util.List;
@RunWith(WindowTestRunner.class)
public class WindowStateTests extends WindowTestsBase {

    @Before
    public void setUp() {
        when(mWm.mInputManager.getInputDevices()).thenReturn(new InputDevice[]{
                new InputDevice.Builder().setSources(InputDevice.SOURCE_TOUCHSCREEN).build()
        });
        mWm.onInputDevicesChanged();
    }

    @After
    public void tearDown() {
        mWm.mSensitiveContentPackages.clearBlockedApps();
@@ -343,14 +354,17 @@ public class WindowStateTests extends WindowTestsBase {
                TYPE_MAGNIFICATION_OVERLAY).build();
        final WindowState navPanelWindow = newWindowBuilder("navPanelWindow",
                TYPE_NAVIGATION_BAR_PANEL).build();
        final WindowState navWindow = newWindowBuilder("navWindow", TYPE_NAVIGATION_BAR).build();

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

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

    @Test
@@ -424,6 +438,91 @@ public class WindowStateTests extends WindowTestsBase {
        assertFalse(navWindow.shouldMagnify());
    }

    @Test
    @EnableFlags(com.android.server.accessibility
            .Flags.FLAG_ENABLE_MAGNIFICATION_MAGNIFY_NAV_BAR_AND_IME)
    public void testMagnifyNavBar_WhenImeIsMagnified_shouldNotMagnify() {
        final ContentResolver cr = useFakeSettingsProvider();
        Settings.Secure.putInt(cr,
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME, 1);
        mWm.mSettingsObserver.onChange(true /* selfChange */,
                Settings.Secure.getUriFor(
                        Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME));

        final WindowState navWindow = newWindowBuilder("navWindow", TYPE_NAVIGATION_BAR).build();
        navWindow.setHasSurface(true);

        // Here are examples of devices that should not trigger magnifying nav bar:
        when(mWm.mInputManager.getInputDevices()).thenReturn(new InputDevice[]{
                new InputDevice.Builder().setSources(InputDevice.SOURCE_TOUCHSCREEN).build(),
                new InputDevice.Builder().setSources(InputDevice.SOURCE_GAMEPAD).build(),
                new InputDevice.Builder().setSources(InputDevice.SOURCE_ROTARY_ENCODER).build(),
                // A disabled device.
                new InputDevice.Builder().setSources(InputDevice.SOURCE_MOUSE)
                        .setEnabled(false).build(),
                // A non-full alphabetic keyboard.
                new InputDevice.Builder().setSources(InputDevice.SOURCE_KEYBOARD)
                        .setKeyboardType(InputDevice.KEYBOARD_TYPE_NON_ALPHABETIC).build(),
                // A virtual keyboard.
                new InputDevice.Builder().setSources(InputDevice.SOURCE_KEYBOARD)
                        .setId(KeyCharacterMap.VIRTUAL_KEYBOARD).build(),
        });
        mWm.onInputDevicesChanged();

        assertTrue(mWm.isMagnifyImeEnabled());
        assertFalse(mWm.isMagnifyNavBarEnabled());
        assertFalse(navWindow.shouldMagnify());
    }

    @Test
    @EnableFlags(com.android.server.accessibility
            .Flags.FLAG_ENABLE_MAGNIFICATION_MAGNIFY_NAV_BAR_AND_IME)
    public void testMagnifyNavBar_WhenImeIsMagnified_withMouse_shouldMagnify() {
        final ContentResolver cr = useFakeSettingsProvider();
        Settings.Secure.putInt(cr,
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME, 1);
        mWm.mSettingsObserver.onChange(true /* selfChange */,
                Settings.Secure.getUriFor(
                        Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME));

        final WindowState navWindow = newWindowBuilder("navWindow", TYPE_NAVIGATION_BAR).build();
        navWindow.setHasSurface(true);

        when(mWm.mInputManager.getInputDevices()).thenReturn(new InputDevice[]{
                new InputDevice.Builder().setSources(InputDevice.SOURCE_MOUSE).build()
        });
        mWm.onInputDevicesChanged();

        assertTrue(mWm.isMagnifyImeEnabled());
        assertTrue(mWm.isMagnifyNavBarEnabled());
        assertTrue(navWindow.shouldMagnify());
    }

    @Test
    @EnableFlags(com.android.server.accessibility
            .Flags.FLAG_ENABLE_MAGNIFICATION_MAGNIFY_NAV_BAR_AND_IME)
    public void testMagnifyNavBar_WhenImeIsMagnified_withKeyboard_shouldMagnify() {
        final ContentResolver cr = useFakeSettingsProvider();
        Settings.Secure.putInt(cr,
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME, 1);
        mWm.mSettingsObserver.onChange(true /* selfChange */,
                Settings.Secure.getUriFor(
                        Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME));

        final WindowState navWindow = newWindowBuilder("navWindow", TYPE_NAVIGATION_BAR).build();
        navWindow.setHasSurface(true);

        when(mWm.mInputManager.getInputDevices()).thenReturn(new InputDevice[]{
                new InputDevice.Builder().setSources(InputDevice.SOURCE_KEYBOARD).setKeyboardType(
                        InputDevice.KEYBOARD_TYPE_ALPHABETIC).build()
        });
        mWm.onInputDevicesChanged();

        assertTrue(mWm.isMagnifyImeEnabled());
        assertTrue(mWm.isMagnifyNavBarEnabled());
        assertTrue(navWindow.shouldMagnify());
    }

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