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

Commit e82227a8 authored by Winson Chung's avatar Winson Chung
Browse files

Use input-reported focus for accessibility

- Input is the source of truth for window focus, which is currently
  partially propagated to Accessibility, we need to migrate the
  remaining focus logic to use the input-provided state to ensure
  the embedded windows (which are increasingly used in SysUI) can
  be correctly focused when shown.
- In particular we need to update the WindowInfo.focused state
  consistently for both WindowStates and embedded windows, to
  populate it based on the last reported focused window token,
  which also allows us to remove the duplicate isFocused state in
  AccessibilityWindow itself

Bug: 378565144
Flag: com.android.window.flags.use_input_reported_focus_for_accessibility
Test: atest AccessibilityWindowManagerTest
Change-Id: I2e77b13a0007907e3ba67e779cf759f254ef8191
parent 9b2b4c88
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -126,3 +126,13 @@ flag {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "use_input_reported_focus_for_accessibility"
    namespace: "window_surfaces"
    description: "Use input-reported focus state when composing accessibility window info"
    bug: "424253885"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+8 −1
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import com.android.server.accessibility.AccessibilitySecurityPolicy.Accessibilit
import com.android.server.utils.Slogf;
import com.android.server.wm.AccessibilityWindowsPopulator.AccessibilityWindow;
import com.android.server.wm.WindowManagerInternal;
import com.android.window.flags.Flags;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -2051,7 +2052,13 @@ public class AccessibilityWindowManager {
        if (traceWMEnabled()) {
            logTraceWM("getFocusedWindowToken", "");
        }
        final IBinder token = mWindowManagerInternal.getFocusedWindowTokenFromWindowStates();

        // When useInputReportedFocusForAccessibility() is enabled, we use the focused input target
        // as reported from input, which may not be reported as the focused window state if the
        // focused input target is an embedded window
        final IBinder token = Flags.useInputReportedFocusForAccessibility()
                ? mWindowManagerInternal.getFocusedWindowToken()
                : mWindowManagerInternal.getFocusedWindowTokenFromWindowStates();
        synchronized (mLock) {
            return findWindowIdLocked(userId, token);
        }
+24 −14
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ import com.android.server.wm.AccessibilityWindowsPopulator.AccessibilityWindow;
import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal;
import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
import com.android.window.flags.Flags;

import java.io.File;
import java.io.IOException;
@@ -205,7 +206,7 @@ final class AccessibilityController {
                mWindowsForAccessibilityObserver.remove(displayId);
            }
            mAccessibilityWindowsPopulator.setWindowsNotification(true);
            observer = new WindowsForAccessibilityObserver(mService, displayId, callback,
            observer = new WindowsForAccessibilityObserver(this, mService, displayId, callback,
                    mAccessibilityWindowsPopulator);
            mWindowsForAccessibilityObserver.put(displayId, observer);
            mAllObserversInitialized &= observer.mInitialized;
@@ -1147,6 +1148,8 @@ final class AccessibilityController {

        private static final boolean DEBUG = false;

        private final AccessibilityController mAccessibilityController;

        private final WindowManagerService mService;

        private final Handler mHandler;
@@ -1163,9 +1166,11 @@ final class AccessibilityController {
        private boolean mInitialized;
        private final AccessibilityWindowsPopulator mA11yWindowsPopulator;

        WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
                int displayId, WindowsForAccessibilityCallback callback,
        WindowsForAccessibilityObserver(AccessibilityController accessibilityController,
                WindowManagerService windowManagerService, int displayId,
                WindowsForAccessibilityCallback callback,
                AccessibilityWindowsPopulator accessibilityWindowsPopulator) {
            mAccessibilityController = accessibilityController;
            mService = windowManagerService;
            mCallback = callback;
            mDisplayId = displayId;
@@ -1218,8 +1223,21 @@ final class AccessibilityController {
            final IBinder topFocusedWindowToken;

            synchronized (mService.mGlobalLock) {
                final WindowState topFocusedWindowState = getTopFocusWindow();
                if (topFocusedWindowState == null) {
                // Gets the top focused display Id and window token for supporting multi-display.
                if (Flags.useInputReportedFocusForAccessibility()) {
                    topFocusedDisplayId = mAccessibilityController.mFocusedDisplay;
                    topFocusedWindowToken = mAccessibilityController.mFocusedWindow.get(
                            topFocusedDisplayId);
                } else {
                    final WindowState topFocusedWindowState =
                            mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
                    topFocusedDisplayId = mService.mRoot.getTopFocusedDisplayContent()
                            .getDisplayId();
                    topFocusedWindowToken = topFocusedWindowState != null
                            ? topFocusedWindowState.mClient.asBinder()
                            : null;
                }
                if (topFocusedWindowToken == null) {
                    if (DEBUG) {
                        Slog.d(LOG_TAG, "top focused window is null, compute it again later");
                    }
@@ -1236,11 +1254,7 @@ final class AccessibilityController {
                display.getRealSize(screenSize);

                mA11yWindowsPopulator.populateVisibleWindowsOnScreenLocked(
                        mDisplayId, visibleWindows);

                // Gets the top focused display Id and window token for supporting multi-display.
                topFocusedDisplayId = mService.mRoot.getTopFocusedDisplayContent().getDisplayId();
                topFocusedWindowToken = topFocusedWindowState.mClient.asBinder();
                        mDisplayId, visibleWindows, topFocusedWindowToken);
            }

            mCallback.onAccessibilityWindowsChanged(forceSend, topFocusedDisplayId,
@@ -1253,10 +1267,6 @@ final class AccessibilityController {
            mInitialized = true;
        }

        private WindowState getTopFocusWindow() {
            return mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
        }

        @Override
        public String toString() {
            return "WindowsForAccessibilityObserver{"
+20 −8
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.view.WindowManager;
import android.window.WindowInfosListener;

import com.android.internal.annotations.GuardedBy;
import com.android.window.flags.Flags;

import java.io.PrintWriter;
import java.util.ArrayList;
@@ -108,9 +109,11 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
     * @param displayId The display.
     * @param outWindows The visible windows list. The z-order of each window in the list
     *                   is from the top to bottom.
     * @param topFocusedWindowToken The top focused window token, used to determine WindowInfo
     *                              focused state
     */
    public void populateVisibleWindowsOnScreenLocked(int displayId,
            List<AccessibilityWindow> outWindows) {
            List<AccessibilityWindow> outWindows, IBinder topFocusedWindowToken) {
        List<InputWindowHandle> inputWindowHandles;
        final Matrix inverseMatrix = new Matrix();
        final Matrix displayMatrix = new Matrix();
@@ -129,7 +132,7 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
                displayMatrix.set(displayInfo.mTransform);
            } else {
                Slog.w(TAG, "The displayInfo of this displayId (" + displayId + ") called "
                        + "back from the surface fligner is null");
                        + "back from the surface flinger is null");
            }
        }

@@ -141,7 +144,7 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
        for (final InputWindowHandle windowHandle : inputWindowHandles) {
            final AccessibilityWindow accessibilityWindow =
                    AccessibilityWindow.initializeData(mService, windowHandle, inverseMatrix,
                            pipMenuIBinder, displayMatrix);
                            pipMenuIBinder, displayMatrix, topFocusedWindowToken);

            outWindows.add(accessibilityWindow);
        }
@@ -653,6 +656,8 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
        private int mInputConfig;
        private int mPrivateFlags;
        private boolean mIsPIPMenu;
        // Only used if Flags.useInputReportedFocusForAccessibility() is false
        // TODO(b/378565144): Remove with Flags.useInputReportedFocusForAccessibility()
        private boolean mIsFocused;
        private boolean mShouldMagnify;
        private final Region mTouchableRegionInScreen = new Region();
@@ -669,7 +674,7 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
         */
        public static AccessibilityWindow initializeData(WindowManagerService service,
                InputWindowHandle inputWindowHandle, Matrix magnificationInverseMatrix,
                IBinder pipIBinder, Matrix displayMatrix) {
                IBinder pipIBinder, Matrix displayMatrix, IBinder topFocusedWindowToken) {
            final IBinder window = inputWindowHandle.getWindowToken();
            final WindowState windowState = window != null ? service.mWindowMap.get(window) : null;

@@ -683,8 +688,10 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {

            // TODO (b/199357848): gets the private flag of the window from other way.
            instance.mPrivateFlags = windowState != null ? windowState.mAttrs.privateFlags : 0;
            if (!Flags.useInputReportedFocusForAccessibility()) {
                // TODO (b/199358208) : using new way to implement the focused window.
                instance.mIsFocused = windowState != null && windowState.isFocused();
            }
            instance.mShouldMagnify = windowState == null || windowState.shouldMagnify();

            final Rect windowFrame = new Rect(inputWindowHandle.frame);
@@ -696,6 +703,9 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
                    magnificationInverseMatrix, displayMatrix);
            instance.mWindowInfo = windowState != null
                    ? windowState.getWindowInfo() : getWindowInfoForWindowlessWindows(instance);
            if (Flags.useInputReportedFocusForAccessibility()) {
                instance.mWindowInfo.focused = window.equals(topFocusedWindowToken);
            }

            // Compute the transform matrix that will transform bounds from the window
            // coordinates to screen coordinates.
@@ -779,7 +789,9 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
         * @return true if this window is focused.
         */
        public boolean isFocused() {
            return mIsFocused;
            return Flags.useInputReportedFocusForAccessibility()
                    ? mWindowInfo.focused
                    : mIsFocused;
        }

        /**
@@ -890,7 +902,7 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
                    + ", inputConfig=0x" + Integer.toHexString(mInputConfig)
                    + ", type=" + mType
                    + ", privateFlag=0x" + Integer.toHexString(mPrivateFlags)
                    + ", focused=" + mIsFocused
                    + ", focused=" + isFocused()
                    + ", shouldMagnify=" + mShouldMagnify
                    + ", isTrustedOverlay=" + isTrustedOverlay()
                    + ", regionInScreen=" + mTouchableRegionInScreen
+1 −0
Original line number Diff line number Diff line
@@ -803,6 +803,7 @@ public class WindowManagerService extends IWindowManager.Stub
    final WindowContextListenerController mWindowContextListenerController =
            new WindowContextListenerController();

    // The currently focused input target (window or embedded window) as reported from input
    private InputTarget mFocusedInputTarget;

    @VisibleForTesting
Loading