Loading services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +4 −5 Original line number Diff line number Diff line Loading @@ -142,7 +142,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ protected final SystemSupport mSystemSupport; protected final WindowManagerInternal mWindowManagerService; private final SystemActionPerformer mSystemActionPerformer; private final AccessibilityWindowManager mA11yWindowManager; final AccessibilityWindowManager mA11yWindowManager; private final DisplayManager mDisplayManager; private final PowerManager mPowerManager; private final IPlatformCompat mIPlatformCompat; Loading Loading @@ -2006,15 +2006,14 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ return accessibilityWindowId; } private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) { int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) { if (windowId == AccessibilityWindowInfo.ANY_WINDOW_ID) { final int focusedWindowId = mA11yWindowManager.getFocusedWindowId(focusType); // If the caller is a proxy and the found window doesn't belong to a proxy display // (or vice versa), then return null. This doesn't work if there are multiple active // proxys, but in the future this code shouldn't be needed if input and a11y focus are // proxys, but in the future this code shouldn't be needed if input focus are // properly split. (so we will deal with the issues if we see them). //TODO(254545943): Remove this when there is user and proxy separation of input and a11y // focus //TODO(254545943): Remove this when there is user and proxy separation of input focus if (!mA11yWindowManager.windowIdBelongsToDisplayType(focusedWindowId, mDisplayTypes)) { return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; } Loading services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +1 −1 Original line number Diff line number Diff line Loading @@ -3823,7 +3823,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub try { mProxyManager.registerProxy(client, displayId, mContext, sIdCounter++, mMainHandler, mSecurityPolicy, this, getTraceManager(), mWindowManagerService, mA11yWindowManager); mWindowManagerService); synchronized (mLock) { notifyClearAccessibilityCacheLocked(); Loading services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java +159 −9 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.accessibility; import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION; import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_DEFAULT; Loading Loading @@ -104,6 +105,8 @@ public class AccessibilityWindowManager { private boolean mTouchInteractionInProgress; private boolean mHasProxy; /** List of Display Windows Observer, mapping from displayId -> DisplayWindowsObserver. */ private final SparseArray<DisplayWindowsObserver> mDisplayWindowsObservers = new SparseArray<>(); Loading Loading @@ -159,6 +162,9 @@ public class AccessibilityWindowManager { * Returns {@code true} if the window belongs to a display of {@code displayTypes}. */ public boolean windowIdBelongsToDisplayType(int focusedWindowId, int displayTypes) { if (!mHasProxy) { return true; } // UIAutomation wants focus from any display type. final int displayTypeMask = DISPLAY_TYPE_PROXY | DISPLAY_TYPE_DEFAULT; if ((displayTypes & displayTypeMask) == displayTypeMask) { Loading Loading @@ -195,6 +201,7 @@ public class AccessibilityWindowManager { private List<AccessibilityWindowInfo> mWindows; private boolean mTrackingWindows = false; private boolean mHasWatchOutsideTouchWindow; private int mProxyDisplayAccessibilityFocusedWindow; private boolean mIsProxy; /** Loading Loading @@ -608,8 +615,11 @@ public class AccessibilityWindowManager { final int windowCount = windows.size(); final boolean isTopFocusedDisplay = mDisplayId == mTopFocusedDisplayId; // A proxy with an a11y-focused window is a11y-focused should use the proxy focus id. final boolean isAccessibilityFocusedDisplay = mDisplayId == mAccessibilityFocusedDisplayId; mDisplayId == mAccessibilityFocusedDisplayId || (mIsProxy && mProxyDisplayAccessibilityFocusedWindow != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID); // Modifies the value of top focused window, active window and a11y focused window // only if this display is top focused display which has the top focused window. if (isTopFocusedDisplay) { Loading @@ -635,8 +645,11 @@ public class AccessibilityWindowManager { // We'll clear accessibility focus if the window with focus is no longer visible to // accessibility services. int a11yFocusedWindowId = mIsProxy ? mProxyDisplayAccessibilityFocusedWindow : mAccessibilityFocusedWindowId; if (isAccessibilityFocusedDisplay) { shouldClearAccessibilityFocus = mAccessibilityFocusedWindowId shouldClearAccessibilityFocus = a11yFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; } Loading Loading @@ -701,7 +714,7 @@ public class AccessibilityWindowManager { if (isAccessibilityFocusedDisplay) { for (int i = 0; i < accessibilityWindowCount; i++) { final AccessibilityWindowInfo window = mWindows.get(i); if (window.getId() == mAccessibilityFocusedWindowId) { if (window.getId() == a11yFocusedWindowId) { window.setAccessibilityFocused(true); shouldClearAccessibilityFocus = false; break; Loading @@ -718,7 +731,7 @@ public class AccessibilityWindowManager { } if (shouldClearAccessibilityFocus) { clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId); clearAccessibilityFocusLocked(a11yFocusedWindowId); } } Loading Loading @@ -1022,6 +1035,7 @@ public class AccessibilityWindowManager { } if (proxyed && !observer.mIsProxy) { observer.mIsProxy = true; mHasProxy = true; } if (observer.isTrackingWindowsLocked()) { return; Loading @@ -1044,6 +1058,7 @@ public class AccessibilityWindowManager { observer.stopTrackingWindowsLocked(); mDisplayWindowsObservers.remove(displayId); } resetHasProxyIfNeededLocked(); } } Loading @@ -1053,11 +1068,26 @@ public class AccessibilityWindowManager { */ public void stopTrackingDisplayProxy(int displayId) { synchronized (mLock) { DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId); final DisplayWindowsObserver proxyObserver = mDisplayWindowsObservers.get(displayId); if (proxyObserver != null) { proxyObserver.mIsProxy = false; } resetHasProxyIfNeededLocked(); } } private void resetHasProxyIfNeededLocked() { boolean hasProxy = false; final int count = mDisplayWindowsObservers.size(); for (int i = 0; i < count; i++) { final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); if (observer != null) { observer.mIsProxy = false; if (observer.mIsProxy) { hasProxy = true; } } } mHasProxy = hasProxy; } /** Loading Loading @@ -1490,6 +1520,11 @@ public class AccessibilityWindowManager { case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: { synchronized (mLock) { // If window id belongs to a proxy display, then find the display, update the // observer focus and send WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED events. if (mHasProxy && setProxyFocusLocked(windowId)) { return; } if (mAccessibilityFocusedWindowId != windowId) { clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId); setAccessibilityFocusedWindowLocked(windowId); Loading @@ -1500,6 +1535,10 @@ public class AccessibilityWindowManager { case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: { synchronized (mLock) { // If cleared happened on the proxy display, then clear the tracked focus. if (mHasProxy && clearProxyFocusLocked(windowId, eventAction)) { return; } if (mAccessibilityFocusNodeId == nodeId) { mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; } Loading Loading @@ -1599,9 +1638,10 @@ public class AccessibilityWindowManager { if (mAccessibilityFocusedDisplayId != Display.INVALID_DISPLAY && mAccessibilityFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) { // Previously focused window -> send a focused event for losing focus events.add(AccessibilityEvent.obtainWindowsChangedEvent( mAccessibilityFocusedDisplayId, mAccessibilityFocusedWindowId, AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); } mAccessibilityFocusedWindowId = windowId; Loading @@ -1611,8 +1651,9 @@ public class AccessibilityWindowManager { final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); if (observer != null && observer.setAccessibilityFocusedWindowLocked(windowId)) { mAccessibilityFocusedDisplayId = observer.mDisplayId; // Newly focused window -> send a focused event for gaining focus events.add(AccessibilityEvent.obtainWindowsChangedEvent(observer.mDisplayId, windowId, AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); windowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); } } Loading Loading @@ -1662,6 +1703,33 @@ public class AccessibilityWindowManager { * @return The focused windowId */ public int getFocusedWindowId(int focusType) { return getFocusedWindowId(focusType, Display.INVALID_DISPLAY); } /** * Returns focused windowId or accessibility focused windowId according to given focusType and * display id. * @param focusType {@link AccessibilityNodeInfo#FOCUS_INPUT} or * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY} * @param displayId the display id to check. If this display is proxy-ed, the proxy's a11y focus * will be returned. * @return The focused windowId */ public int getFocusedWindowId(int focusType, int displayId) { if (displayId == Display.INVALID_DISPLAY || displayId == Display.DEFAULT_DISPLAY || !mHasProxy) { return getDefaultFocus(focusType); } final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId); if (observer != null && observer.mIsProxy) { return getProxyFocus(focusType, observer); } else { return getDefaultFocus(focusType); } } private int getDefaultFocus(int focusType) { if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) { return mTopFocusedWindowId; } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) { Loading @@ -1670,6 +1738,16 @@ public class AccessibilityWindowManager { return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; } private int getProxyFocus(int focusType, DisplayWindowsObserver observer) { if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) { return mTopFocusedWindowId; } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) { return observer.mProxyDisplayAccessibilityFocusedWindow; } else { return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; } } /** * Returns {@link AccessibilityWindowInfo} of PIP window. * Loading Loading @@ -1987,6 +2065,78 @@ public class AccessibilityWindowManager { return mHostEmbeddedMap.get(token); } /** * Checks if the window belongs to a proxy display and if so clears the focused window id. * @param focusClearedWindowId the cleared window id. * @return true if an observer is proxy-ed and has cleared its focused window id. */ private boolean clearProxyFocusLocked(int focusClearedWindowId, int eventAction) { // If we are just moving focus from one view to the other in the same window, do nothing. if (eventAction == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS) { return false; } for (int i = 0; i < mDisplayWindowsObservers.size(); i++) { final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(i); if (observer != null && observer.mWindows != null && observer.mIsProxy) { final int windowCount = observer.mWindows.size(); for (int j = 0; j < windowCount; j++) { AccessibilityWindowInfo window = observer.mWindows.get(j); if (window.getId() == focusClearedWindowId) { observer.mProxyDisplayAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; // TODO(268754409): Look into sending a WINDOW_FOCUS_CHANGED event since // window no longer has focus (default window logic doesn't), and // whether the node id needs to be cached (default window logic does). return true; } } } } return false; } /** * Checks if the window belongs to a proxy display and if so sends * WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED for that window and the previously focused window. * @param focusedWindowId the focused window id. * @return true if an observer is proxy-ed and contains the focused window. */ private boolean setProxyFocusLocked(int focusedWindowId) { for (int i = 0; i < mDisplayWindowsObservers.size(); i++) { final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); if (observer != null && observer.mIsProxy && observer.setAccessibilityFocusedWindowLocked(focusedWindowId)) { final int previouslyFocusedWindowId = observer.mProxyDisplayAccessibilityFocusedWindow; if (previouslyFocusedWindowId == focusedWindowId) { // Don't send a focus event if the window is already focused. return true; } // Previously focused window -> Clear focus on UI thread and send a focused event // for losing focus if (previouslyFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) { clearAccessibilityFocusLocked(previouslyFocusedWindowId); mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( AccessibilityEvent.obtainWindowsChangedEvent( observer.mDisplayId, previouslyFocusedWindowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); } observer.mProxyDisplayAccessibilityFocusedWindow = focusedWindowId; // Newly focused window -> send a focused event for it gaining focus mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( AccessibilityEvent.obtainWindowsChangedEvent( observer.mDisplayId, observer.mProxyDisplayAccessibilityFocusedWindow, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); return true; } } return false; } /** * Dumps all {@link AccessibilityWindowInfo}s here. */ Loading services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java +18 −0 Original line number Diff line number Diff line Loading @@ -254,6 +254,24 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon return mFocusColor; } @Override int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) { if (windowId == AccessibilityWindowInfo.ANY_WINDOW_ID) { final int focusedWindowId = mA11yWindowManager.getFocusedWindowId(focusType, mDisplayId); // If the caller is a proxy and the found window doesn't belong to a proxy display // (or vice versa), then return null. This doesn't work if there are multiple active // proxys, but in the future this code shouldn't be needed if input focus // properly split. (so we will deal with the issues if we see them). //TODO(254545943): Remove this when there is user and proxy separation of input if (!mA11yWindowManager.windowIdBelongsToDisplayType(focusedWindowId, mDisplayTypes)) { return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; } return focusedWindowId; } return windowId; } @Override public void binderDied() { } Loading services/accessibility/java/com/android/server/accessibility/ProxyManager.java +2 −3 Original line number Diff line number Diff line Loading @@ -78,8 +78,7 @@ public class ProxyManager { AccessibilitySecurityPolicy securityPolicy, AbstractAccessibilityServiceConnection.SystemSupport systemSupport, AccessibilityTrace trace, WindowManagerInternal windowManagerInternal, AccessibilityWindowManager awm) throws RemoteException { WindowManagerInternal windowManagerInternal) throws RemoteException { // Set a default AccessibilityServiceInfo that is used before the proxy's info is // populated. A proxy has the touch exploration and window capabilities. Loading @@ -93,7 +92,7 @@ public class ProxyManager { new ProxyAccessibilityServiceConnection(context, info.getComponentName(), info, id, mainHandler, mLock, securityPolicy, systemSupport, trace, windowManagerInternal, awm, displayId); mA11yWindowManager, displayId); synchronized (mLock) { mProxyA11yServiceConnections.put(displayId, connection); Loading Loading
services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +4 −5 Original line number Diff line number Diff line Loading @@ -142,7 +142,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ protected final SystemSupport mSystemSupport; protected final WindowManagerInternal mWindowManagerService; private final SystemActionPerformer mSystemActionPerformer; private final AccessibilityWindowManager mA11yWindowManager; final AccessibilityWindowManager mA11yWindowManager; private final DisplayManager mDisplayManager; private final PowerManager mPowerManager; private final IPlatformCompat mIPlatformCompat; Loading Loading @@ -2006,15 +2006,14 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ return accessibilityWindowId; } private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) { int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) { if (windowId == AccessibilityWindowInfo.ANY_WINDOW_ID) { final int focusedWindowId = mA11yWindowManager.getFocusedWindowId(focusType); // If the caller is a proxy and the found window doesn't belong to a proxy display // (or vice versa), then return null. This doesn't work if there are multiple active // proxys, but in the future this code shouldn't be needed if input and a11y focus are // proxys, but in the future this code shouldn't be needed if input focus are // properly split. (so we will deal with the issues if we see them). //TODO(254545943): Remove this when there is user and proxy separation of input and a11y // focus //TODO(254545943): Remove this when there is user and proxy separation of input focus if (!mA11yWindowManager.windowIdBelongsToDisplayType(focusedWindowId, mDisplayTypes)) { return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; } Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +1 −1 Original line number Diff line number Diff line Loading @@ -3823,7 +3823,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub try { mProxyManager.registerProxy(client, displayId, mContext, sIdCounter++, mMainHandler, mSecurityPolicy, this, getTraceManager(), mWindowManagerService, mA11yWindowManager); mWindowManagerService); synchronized (mLock) { notifyClearAccessibilityCacheLocked(); Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java +159 −9 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.accessibility; import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION; import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_DEFAULT; Loading Loading @@ -104,6 +105,8 @@ public class AccessibilityWindowManager { private boolean mTouchInteractionInProgress; private boolean mHasProxy; /** List of Display Windows Observer, mapping from displayId -> DisplayWindowsObserver. */ private final SparseArray<DisplayWindowsObserver> mDisplayWindowsObservers = new SparseArray<>(); Loading Loading @@ -159,6 +162,9 @@ public class AccessibilityWindowManager { * Returns {@code true} if the window belongs to a display of {@code displayTypes}. */ public boolean windowIdBelongsToDisplayType(int focusedWindowId, int displayTypes) { if (!mHasProxy) { return true; } // UIAutomation wants focus from any display type. final int displayTypeMask = DISPLAY_TYPE_PROXY | DISPLAY_TYPE_DEFAULT; if ((displayTypes & displayTypeMask) == displayTypeMask) { Loading Loading @@ -195,6 +201,7 @@ public class AccessibilityWindowManager { private List<AccessibilityWindowInfo> mWindows; private boolean mTrackingWindows = false; private boolean mHasWatchOutsideTouchWindow; private int mProxyDisplayAccessibilityFocusedWindow; private boolean mIsProxy; /** Loading Loading @@ -608,8 +615,11 @@ public class AccessibilityWindowManager { final int windowCount = windows.size(); final boolean isTopFocusedDisplay = mDisplayId == mTopFocusedDisplayId; // A proxy with an a11y-focused window is a11y-focused should use the proxy focus id. final boolean isAccessibilityFocusedDisplay = mDisplayId == mAccessibilityFocusedDisplayId; mDisplayId == mAccessibilityFocusedDisplayId || (mIsProxy && mProxyDisplayAccessibilityFocusedWindow != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID); // Modifies the value of top focused window, active window and a11y focused window // only if this display is top focused display which has the top focused window. if (isTopFocusedDisplay) { Loading @@ -635,8 +645,11 @@ public class AccessibilityWindowManager { // We'll clear accessibility focus if the window with focus is no longer visible to // accessibility services. int a11yFocusedWindowId = mIsProxy ? mProxyDisplayAccessibilityFocusedWindow : mAccessibilityFocusedWindowId; if (isAccessibilityFocusedDisplay) { shouldClearAccessibilityFocus = mAccessibilityFocusedWindowId shouldClearAccessibilityFocus = a11yFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; } Loading Loading @@ -701,7 +714,7 @@ public class AccessibilityWindowManager { if (isAccessibilityFocusedDisplay) { for (int i = 0; i < accessibilityWindowCount; i++) { final AccessibilityWindowInfo window = mWindows.get(i); if (window.getId() == mAccessibilityFocusedWindowId) { if (window.getId() == a11yFocusedWindowId) { window.setAccessibilityFocused(true); shouldClearAccessibilityFocus = false; break; Loading @@ -718,7 +731,7 @@ public class AccessibilityWindowManager { } if (shouldClearAccessibilityFocus) { clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId); clearAccessibilityFocusLocked(a11yFocusedWindowId); } } Loading Loading @@ -1022,6 +1035,7 @@ public class AccessibilityWindowManager { } if (proxyed && !observer.mIsProxy) { observer.mIsProxy = true; mHasProxy = true; } if (observer.isTrackingWindowsLocked()) { return; Loading @@ -1044,6 +1058,7 @@ public class AccessibilityWindowManager { observer.stopTrackingWindowsLocked(); mDisplayWindowsObservers.remove(displayId); } resetHasProxyIfNeededLocked(); } } Loading @@ -1053,11 +1068,26 @@ public class AccessibilityWindowManager { */ public void stopTrackingDisplayProxy(int displayId) { synchronized (mLock) { DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId); final DisplayWindowsObserver proxyObserver = mDisplayWindowsObservers.get(displayId); if (proxyObserver != null) { proxyObserver.mIsProxy = false; } resetHasProxyIfNeededLocked(); } } private void resetHasProxyIfNeededLocked() { boolean hasProxy = false; final int count = mDisplayWindowsObservers.size(); for (int i = 0; i < count; i++) { final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); if (observer != null) { observer.mIsProxy = false; if (observer.mIsProxy) { hasProxy = true; } } } mHasProxy = hasProxy; } /** Loading Loading @@ -1490,6 +1520,11 @@ public class AccessibilityWindowManager { case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: { synchronized (mLock) { // If window id belongs to a proxy display, then find the display, update the // observer focus and send WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED events. if (mHasProxy && setProxyFocusLocked(windowId)) { return; } if (mAccessibilityFocusedWindowId != windowId) { clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId); setAccessibilityFocusedWindowLocked(windowId); Loading @@ -1500,6 +1535,10 @@ public class AccessibilityWindowManager { case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: { synchronized (mLock) { // If cleared happened on the proxy display, then clear the tracked focus. if (mHasProxy && clearProxyFocusLocked(windowId, eventAction)) { return; } if (mAccessibilityFocusNodeId == nodeId) { mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; } Loading Loading @@ -1599,9 +1638,10 @@ public class AccessibilityWindowManager { if (mAccessibilityFocusedDisplayId != Display.INVALID_DISPLAY && mAccessibilityFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) { // Previously focused window -> send a focused event for losing focus events.add(AccessibilityEvent.obtainWindowsChangedEvent( mAccessibilityFocusedDisplayId, mAccessibilityFocusedWindowId, AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); } mAccessibilityFocusedWindowId = windowId; Loading @@ -1611,8 +1651,9 @@ public class AccessibilityWindowManager { final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); if (observer != null && observer.setAccessibilityFocusedWindowLocked(windowId)) { mAccessibilityFocusedDisplayId = observer.mDisplayId; // Newly focused window -> send a focused event for gaining focus events.add(AccessibilityEvent.obtainWindowsChangedEvent(observer.mDisplayId, windowId, AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); windowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); } } Loading Loading @@ -1662,6 +1703,33 @@ public class AccessibilityWindowManager { * @return The focused windowId */ public int getFocusedWindowId(int focusType) { return getFocusedWindowId(focusType, Display.INVALID_DISPLAY); } /** * Returns focused windowId or accessibility focused windowId according to given focusType and * display id. * @param focusType {@link AccessibilityNodeInfo#FOCUS_INPUT} or * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY} * @param displayId the display id to check. If this display is proxy-ed, the proxy's a11y focus * will be returned. * @return The focused windowId */ public int getFocusedWindowId(int focusType, int displayId) { if (displayId == Display.INVALID_DISPLAY || displayId == Display.DEFAULT_DISPLAY || !mHasProxy) { return getDefaultFocus(focusType); } final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId); if (observer != null && observer.mIsProxy) { return getProxyFocus(focusType, observer); } else { return getDefaultFocus(focusType); } } private int getDefaultFocus(int focusType) { if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) { return mTopFocusedWindowId; } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) { Loading @@ -1670,6 +1738,16 @@ public class AccessibilityWindowManager { return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; } private int getProxyFocus(int focusType, DisplayWindowsObserver observer) { if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) { return mTopFocusedWindowId; } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) { return observer.mProxyDisplayAccessibilityFocusedWindow; } else { return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; } } /** * Returns {@link AccessibilityWindowInfo} of PIP window. * Loading Loading @@ -1987,6 +2065,78 @@ public class AccessibilityWindowManager { return mHostEmbeddedMap.get(token); } /** * Checks if the window belongs to a proxy display and if so clears the focused window id. * @param focusClearedWindowId the cleared window id. * @return true if an observer is proxy-ed and has cleared its focused window id. */ private boolean clearProxyFocusLocked(int focusClearedWindowId, int eventAction) { // If we are just moving focus from one view to the other in the same window, do nothing. if (eventAction == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS) { return false; } for (int i = 0; i < mDisplayWindowsObservers.size(); i++) { final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(i); if (observer != null && observer.mWindows != null && observer.mIsProxy) { final int windowCount = observer.mWindows.size(); for (int j = 0; j < windowCount; j++) { AccessibilityWindowInfo window = observer.mWindows.get(j); if (window.getId() == focusClearedWindowId) { observer.mProxyDisplayAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; // TODO(268754409): Look into sending a WINDOW_FOCUS_CHANGED event since // window no longer has focus (default window logic doesn't), and // whether the node id needs to be cached (default window logic does). return true; } } } } return false; } /** * Checks if the window belongs to a proxy display and if so sends * WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED for that window and the previously focused window. * @param focusedWindowId the focused window id. * @return true if an observer is proxy-ed and contains the focused window. */ private boolean setProxyFocusLocked(int focusedWindowId) { for (int i = 0; i < mDisplayWindowsObservers.size(); i++) { final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); if (observer != null && observer.mIsProxy && observer.setAccessibilityFocusedWindowLocked(focusedWindowId)) { final int previouslyFocusedWindowId = observer.mProxyDisplayAccessibilityFocusedWindow; if (previouslyFocusedWindowId == focusedWindowId) { // Don't send a focus event if the window is already focused. return true; } // Previously focused window -> Clear focus on UI thread and send a focused event // for losing focus if (previouslyFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) { clearAccessibilityFocusLocked(previouslyFocusedWindowId); mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( AccessibilityEvent.obtainWindowsChangedEvent( observer.mDisplayId, previouslyFocusedWindowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); } observer.mProxyDisplayAccessibilityFocusedWindow = focusedWindowId; // Newly focused window -> send a focused event for it gaining focus mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( AccessibilityEvent.obtainWindowsChangedEvent( observer.mDisplayId, observer.mProxyDisplayAccessibilityFocusedWindow, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); return true; } } return false; } /** * Dumps all {@link AccessibilityWindowInfo}s here. */ Loading
services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java +18 −0 Original line number Diff line number Diff line Loading @@ -254,6 +254,24 @@ public class ProxyAccessibilityServiceConnection extends AccessibilityServiceCon return mFocusColor; } @Override int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) { if (windowId == AccessibilityWindowInfo.ANY_WINDOW_ID) { final int focusedWindowId = mA11yWindowManager.getFocusedWindowId(focusType, mDisplayId); // If the caller is a proxy and the found window doesn't belong to a proxy display // (or vice versa), then return null. This doesn't work if there are multiple active // proxys, but in the future this code shouldn't be needed if input focus // properly split. (so we will deal with the issues if we see them). //TODO(254545943): Remove this when there is user and proxy separation of input if (!mA11yWindowManager.windowIdBelongsToDisplayType(focusedWindowId, mDisplayTypes)) { return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; } return focusedWindowId; } return windowId; } @Override public void binderDied() { } Loading
services/accessibility/java/com/android/server/accessibility/ProxyManager.java +2 −3 Original line number Diff line number Diff line Loading @@ -78,8 +78,7 @@ public class ProxyManager { AccessibilitySecurityPolicy securityPolicy, AbstractAccessibilityServiceConnection.SystemSupport systemSupport, AccessibilityTrace trace, WindowManagerInternal windowManagerInternal, AccessibilityWindowManager awm) throws RemoteException { WindowManagerInternal windowManagerInternal) throws RemoteException { // Set a default AccessibilityServiceInfo that is used before the proxy's info is // populated. A proxy has the touch exploration and window capabilities. Loading @@ -93,7 +92,7 @@ public class ProxyManager { new ProxyAccessibilityServiceConnection(context, info.getComponentName(), info, id, mainHandler, mLock, securityPolicy, systemSupport, trace, windowManagerInternal, awm, displayId); mA11yWindowManager, displayId); synchronized (mLock) { mProxyA11yServiceConnections.put(displayId, connection); Loading