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

Commit 1132b1b6 authored by Sally's avatar Sally
Browse files

Force input focus to the last focused non-proxy display.

This only happens under a couple of conditions:

1) An A11yService is about to perform a system action.
2) An A11yService has touch exploration enabled, and
   TouchState has received a TYPE_TOUCH_INTERACTION_END
   AccessibilityEvent, meaning the user has just completed a touch
   interaction.

In both cases, the top focus will only move if the current top focused
display is being proxyed, i.e. the display is being streamed to a
ChromeBook with a11y enabled.

Keep the places where focus changes minimal, since ideally a
VirtualDeviceManager client like Exo should not be stealing focus and
this should be fixed on the input level.

In the fallback case where there is no register system action so we
directly send key events, target the last focused non-proxy display.

Bug: 274511647
Test: atest AccessibilityDisplayProxyTest and manual (see videos in
comments)

Change-Id: I79f5b4806eeed4fd222b811a919ddb296e83a895
parent 2e03f9f5
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -192,7 +192,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        AccessibilityUserState.ServiceInfoChangeListener,
        AccessibilityWindowManager.AccessibilityEventSender,
        AccessibilitySecurityPolicy.AccessibilityUserManager,
        SystemActionPerformer.SystemActionsChangedListener, ProxyManager.SystemSupport{
        SystemActionPerformer.SystemActionsChangedListener,
        SystemActionPerformer.DisplayUpdateCallBack, ProxyManager.SystemSupport {

    private static final boolean DEBUG = false;

@@ -1181,7 +1182,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
    private SystemActionPerformer getSystemActionPerformer() {
        if (mSystemActionPerformer == null) {
            mSystemActionPerformer =
                    new SystemActionPerformer(mContext, mWindowManagerService, null, this);
                    new SystemActionPerformer(mContext, mWindowManagerService, null, this, this);
        }
        return mSystemActionPerformer;
    }
@@ -1531,6 +1532,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        }
    }

    @Override
    // TODO(b/276459590): Remove when this is resolved at the virtual device/input level.
    public void moveNonProxyTopFocusedDisplayToTopIfNeeded() {
        mA11yWindowManager.moveNonProxyTopFocusedDisplayToTopIfNeeded();
    }

    @Override
    // TODO(b/276459590): Remove when this is resolved at the virtual device/input level.
    public int getLastNonProxyTopFocusedDisplayId() {
        return mA11yWindowManager.getLastNonProxyTopFocusedDisplayId();
    }

    @VisibleForTesting
    void notifySystemActionsChangedLocked(AccessibilityUserState userState) {
        for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+21 −0
Original line number Diff line number Diff line
@@ -100,6 +100,9 @@ public class AccessibilityWindowManager {
    // The top focused display and window token updated with the callback of window lists change.
    private int mTopFocusedDisplayId;
    private IBinder mTopFocusedWindowToken;

    // The non-proxy display that most recently had top focus.
    private int mLastNonProxyTopFocusedDisplayId;
    // The display has the accessibility focused window currently.
    private int mAccessibilityFocusedDisplayId = Display.INVALID_DISPLAY;

@@ -434,6 +437,9 @@ public class AccessibilityWindowManager {
                }
                if (shouldUpdateWindowsLocked(forceSend, windows)) {
                    mTopFocusedDisplayId = topFocusedDisplayId;
                    if (!isProxyed(topFocusedDisplayId)) {
                        mLastNonProxyTopFocusedDisplayId = topFocusedDisplayId;
                    }
                    mTopFocusedWindowToken = topFocusedWindowToken;
                    cacheWindows(windows);
                    // Lets the policy update the focused and active windows.
@@ -1108,6 +1114,21 @@ public class AccessibilityWindowManager {
        return false;
    }

    private boolean isProxyed(int displayId) {
        final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId);
        return (observer != null && observer.mIsProxy);
    }

    void moveNonProxyTopFocusedDisplayToTopIfNeeded() {
        if (mHasProxy
                && (mLastNonProxyTopFocusedDisplayId != mTopFocusedDisplayId)) {
            mWindowManagerInternal.moveDisplayToTopIfAllowed(mLastNonProxyTopFocusedDisplayId);
        }
    }
    int getLastNonProxyTopFocusedDisplayId() {
        return mLastNonProxyTopFocusedDisplayId;
    }

    /**
     * Checks if we are tracking windows on specified display.
     *
+14 −4
Original line number Diff line number Diff line
@@ -72,6 +72,13 @@ public class SystemActionPerformer {
    }
    private final SystemActionsChangedListener mListener;

    interface DisplayUpdateCallBack {
        void moveNonProxyTopFocusedDisplayToTopIfNeeded();

        int getLastNonProxyTopFocusedDisplayId();
    }
    private final DisplayUpdateCallBack mDisplayUpdateCallBack;

    private final Object mSystemActionLock = new Object();
    // Resource id based ActionId -> RemoteAction
    @GuardedBy("mSystemActionLock")
@@ -94,7 +101,7 @@ public class SystemActionPerformer {
    public SystemActionPerformer(
            Context context,
            WindowManagerInternal windowManagerInternal) {
      this(context, windowManagerInternal, null, null);
      this(context, windowManagerInternal, null, null, null);
    }

    // Used to mock ScreenshotHelper
@@ -103,17 +110,19 @@ public class SystemActionPerformer {
            Context context,
            WindowManagerInternal windowManagerInternal,
            Supplier<ScreenshotHelper> screenshotHelperSupplier) {
        this(context, windowManagerInternal, screenshotHelperSupplier, null);
        this(context, windowManagerInternal, screenshotHelperSupplier, null, null);
    }

    public SystemActionPerformer(
            Context context,
            WindowManagerInternal windowManagerInternal,
            Supplier<ScreenshotHelper> screenshotHelperSupplier,
            SystemActionsChangedListener listener) {
            SystemActionsChangedListener listener,
            DisplayUpdateCallBack callback) {
        mContext = context;
        mWindowManagerService = windowManagerInternal;
        mListener = listener;
        mDisplayUpdateCallBack = callback;
        mScreenshotHelperSupplier = screenshotHelperSupplier;

        mLegacyHomeAction = new AccessibilityAction(
@@ -245,6 +254,7 @@ public class SystemActionPerformer {
        final long identity = Binder.clearCallingIdentity();
        try {
            synchronized (mSystemActionLock) {
                mDisplayUpdateCallBack.moveNonProxyTopFocusedDisplayToTopIfNeeded();
                // If a system action is registered with the given actionId, call the corresponding
                // RemoteAction.
                RemoteAction registeredAction = mRegisteredSystemActions.get(actionId);
@@ -341,7 +351,7 @@ public class SystemActionPerformer {
            int source) {
        KeyEvent event = KeyEvent.obtain(downTime, time, action, keyCode, 0, 0,
                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
                source, null);
                source, mDisplayUpdateCallBack.getLastNonProxyTopFocusedDisplayId(), null);
        mContext.getSystemService(InputManager.class)
                .injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
        event.recycle();
+3 −0
Original line number Diff line number Diff line
@@ -199,6 +199,9 @@ public class TouchState {
            case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT:
                mLastTouchedWindowId = event.getWindowId();
                break;
            case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
                mAms.moveNonProxyTopFocusedDisplayToTopIfNeeded();
                break;
        }
    }

+5 −0
Original line number Diff line number Diff line
@@ -443,6 +443,11 @@ public abstract class WindowManagerInternal {
     */
    public abstract IBinder getFocusedWindowTokenFromWindowStates();

    /**
     * Moves the given display to the top.
     */
    public abstract void moveDisplayToTopIfAllowed(int displayId);

    /**
     * @return Whether the keyguard is engaged.
     */
Loading