summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/accessibility/AccessibilityEvent.java4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java5
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java68
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java164
4 files changed, 207 insertions, 34 deletions
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 2db0dcbce45e..7d8f363bf81c 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -1332,6 +1332,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* Convenience method to obtain a {@link #TYPE_WINDOWS_CHANGED} event for a specific window and
* change set.
*
+ * @param displayId The ID of the display from which the event comes from
* @param windowId The ID of the window that changed
* @param windowChangeTypes The changes to populate
* @return An instance of a TYPE_WINDOWS_CHANGED, populated with the requested fields and with
@@ -1340,8 +1341,9 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* @hide
*/
public static AccessibilityEvent obtainWindowsChangedEvent(
- int windowId, int windowChangeTypes) {
+ int displayId, int windowId, int windowChangeTypes) {
final AccessibilityEvent event = new AccessibilityEvent(TYPE_WINDOWS_CHANGED);
+ event.setDisplayId(displayId);
event.setWindowId(windowId);
event.setWindowChanges(windowChangeTypes);
event.setImportantForAccessibility(true);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 6a6d2bb44d48..098e0245c32d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -952,10 +952,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// current state of the windows as the window manager may be delaying
// the computation for performance reasons.
boolean shouldComputeWindows = false;
- int displayId = Display.INVALID_DISPLAY;
+ int displayId = event.getDisplayId();
synchronized (mLock) {
final int windowId = event.getWindowId();
- if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
+ if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID
+ && displayId == Display.INVALID_DISPLAY) {
displayId = mA11yWindowManager.getDisplayIdByUserIdAndWindowIdLocked(
resolvedUserId, windowId);
event.setDisplayId(displayId);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index d33e7b2e4d87..7c68c8a5bdb1 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -19,7 +19,6 @@ 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;
@@ -275,22 +274,23 @@ public class AccessibilityWindowManager {
* Sets the active flag of the window according to given windowId, others set to inactive.
*
* @param windowId The windowId
+ * @return {@code true} if the window is in this display, {@code false} otherwise.
*/
- void setActiveWindowLocked(int windowId) {
+ boolean setActiveWindowLocked(int windowId) {
+ boolean foundWindow = false;
if (mWindows != null) {
final int windowCount = mWindows.size();
for (int i = 0; i < windowCount; i++) {
AccessibilityWindowInfo window = mWindows.get(i);
if (window.getId() == windowId) {
window.setActive(true);
- mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
- AccessibilityEvent.obtainWindowsChangedEvent(windowId,
- AccessibilityEvent.WINDOWS_CHANGE_ACTIVE));
+ foundWindow = true;
} else {
window.setActive(false);
}
}
}
+ return foundWindow;
}
/**
@@ -298,24 +298,23 @@ public class AccessibilityWindowManager {
* unfocused.
*
* @param windowId The windowId
+ * @return {@code true} if the window is in this display, {@code false} otherwise.
*/
- void setAccessibilityFocusedWindowLocked(int windowId) {
+ boolean setAccessibilityFocusedWindowLocked(int windowId) {
+ boolean foundWindow = false;
if (mWindows != null) {
final int windowCount = mWindows.size();
for (int i = 0; i < windowCount; i++) {
AccessibilityWindowInfo window = mWindows.get(i);
if (window.getId() == windowId) {
- mAccessibilityFocusedDisplayId = mDisplayId;
window.setAccessibilityFocused(true);
- mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
- AccessibilityEvent.obtainWindowsChangedEvent(
- windowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
-
+ foundWindow = true;
} else {
window.setAccessibilityFocused(false);
}
}
}
+ return foundWindow;
}
/**
@@ -704,7 +703,7 @@ public class AccessibilityWindowManager {
final AccessibilityWindowInfo window = oldWindows.get(i);
if (mA11yWindowInfoById.get(window.getId()) == null) {
events.add(AccessibilityEvent.obtainWindowsChangedEvent(
- window.getId(), AccessibilityEvent.WINDOWS_CHANGE_REMOVED));
+ mDisplayId, window.getId(), AccessibilityEvent.WINDOWS_CHANGE_REMOVED));
}
}
@@ -714,13 +713,13 @@ public class AccessibilityWindowManager {
final AccessibilityWindowInfo newWindow = mWindows.get(i);
final AccessibilityWindowInfo oldWindow = oldWindowsById.get(newWindow.getId());
if (oldWindow == null) {
- events.add(AccessibilityEvent.obtainWindowsChangedEvent(
+ events.add(AccessibilityEvent.obtainWindowsChangedEvent(mDisplayId,
newWindow.getId(), AccessibilityEvent.WINDOWS_CHANGE_ADDED));
} else {
int changes = newWindow.differenceFrom(oldWindow);
if (changes != 0) {
events.add(AccessibilityEvent.obtainWindowsChangedEvent(
- newWindow.getId(), changes));
+ mDisplayId, newWindow.getId(), changes));
}
}
}
@@ -1522,38 +1521,59 @@ public class AccessibilityWindowManager {
private void setActiveWindowLocked(int windowId) {
if (mActiveWindowId != windowId) {
- mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
- AccessibilityEvent.obtainWindowsChangedEvent(
+ List<AccessibilityEvent> events = new ArrayList<>(2);
+ if (mActiveWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
+ final DisplayWindowsObserver observer =
+ getDisplayWindowObserverByWindowIdLocked(mActiveWindowId);
+ if (observer != null) {
+ events.add(AccessibilityEvent.obtainWindowsChangedEvent(observer.mDisplayId,
mActiveWindowId, AccessibilityEvent.WINDOWS_CHANGE_ACTIVE));
+ }
+ }
mActiveWindowId = windowId;
// Goes through all windows for each display.
final int count = mDisplayWindowsObservers.size();
for (int i = 0; i < count; i++) {
final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i);
- if (observer != null) {
- observer.setActiveWindowLocked(windowId);
+ if (observer != null && observer.setActiveWindowLocked(windowId)) {
+ events.add(AccessibilityEvent.obtainWindowsChangedEvent(observer.mDisplayId,
+ windowId, AccessibilityEvent.WINDOWS_CHANGE_ACTIVE));
}
}
+
+ for (final AccessibilityEvent event : events) {
+ mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(event);
+ }
}
}
private void setAccessibilityFocusedWindowLocked(int windowId) {
if (mAccessibilityFocusedWindowId != windowId) {
- mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
- AccessibilityEvent.obtainWindowsChangedEvent(
- mAccessibilityFocusedWindowId,
- WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
+ List<AccessibilityEvent> events = new ArrayList<>(2);
+ if (mAccessibilityFocusedDisplayId != Display.INVALID_DISPLAY
+ && mAccessibilityFocusedWindowId
+ != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
+ events.add(AccessibilityEvent.obtainWindowsChangedEvent(
+ mAccessibilityFocusedDisplayId, mAccessibilityFocusedWindowId,
+ AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
+ }
mAccessibilityFocusedWindowId = windowId;
// Goes through all windows for each display.
final int count = mDisplayWindowsObservers.size();
for (int i = 0; i < count; i++) {
final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i);
- if (observer != null) {
- observer.setAccessibilityFocusedWindowLocked(windowId);
+ if (observer != null && observer.setAccessibilityFocusedWindowLocked(windowId)) {
+ mAccessibilityFocusedDisplayId = observer.mDisplayId;
+ events.add(AccessibilityEvent.obtainWindowsChangedEvent(observer.mDisplayId,
+ windowId, AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
}
}
+
+ for (final AccessibilityEvent event : events) {
+ mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(event);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index c7757f7832fa..acbcad54626d 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -16,6 +16,7 @@
package com.android.server.accessibility;
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.DisplayIdMatcher.displayId;
import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowChangesMatcher.a11yWindowChanges;
import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowIdMatcher.a11yWindowId;
@@ -587,10 +588,12 @@ public class AccessibilityWindowManagerTest {
verify(mMockA11yEventSender, times(2))
.sendAccessibilityEventForCurrentUserLocked(captor.capture());
assertThat(captor.getAllValues().get(0),
- allOf(a11yWindowId(currentActiveWindowId),
+ allOf(displayId(Display.DEFAULT_DISPLAY),
+ a11yWindowId(currentActiveWindowId),
a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
assertThat(captor.getAllValues().get(1),
- allOf(a11yWindowId(eventWindowId),
+ allOf(displayId(Display.DEFAULT_DISPLAY),
+ a11yWindowId(eventWindowId),
a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
}
@@ -600,10 +603,59 @@ public class AccessibilityWindowManagerTest {
DEFAULT_FOCUSED_INDEX);
final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
- assertThat(currentA11yFocusedWindowId, is(not(eventWindowId)));
+ assertThat(currentA11yFocusedWindowId, is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
+
+ final int noUse = 0;
+ mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+ eventWindowId,
+ AccessibilityNodeInfo.ROOT_NODE_ID,
+ AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+ noUse);
+ assertThat(mA11yWindowManager.getFocusedWindowId(
+ AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
+ final ArgumentCaptor<AccessibilityEvent> captor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+ verify(mMockA11yEventSender, times(1))
+ .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+ assertThat(captor.getAllValues().get(0),
+ allOf(displayId(Display.DEFAULT_DISPLAY),
+ a11yWindowId(eventWindowId),
+ a11yWindowChanges(
+ AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
+ }
+
+ @Test
+ public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_defaultToSecondary()
+ throws RemoteException {
+ runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
+ Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID);
+ }
+
+ @Test
+ public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_SecondaryToDefault()
+ throws RemoteException {
+ runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
+ SECONDARY_DISPLAY_ID, Display.DEFAULT_DISPLAY);
+ }
+ private void runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
+ int initialDisplayId, int eventDisplayId) throws RemoteException {
+ startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+ final int initialWindowId = getWindowIdFromWindowInfosForDisplay(
+ initialDisplayId, DEFAULT_FOCUSED_INDEX);
final int noUse = 0;
mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+ initialWindowId,
+ AccessibilityNodeInfo.ROOT_NODE_ID,
+ AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+ noUse);
+ assertThat(mA11yWindowManager.getFocusedWindowId(
+ AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(initialWindowId));
+ Mockito.reset(mMockA11yEventSender);
+
+ final int eventWindowId = getWindowIdFromWindowInfosForDisplay(
+ eventDisplayId, DEFAULT_FOCUSED_INDEX);
+ mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
eventWindowId,
AccessibilityNodeInfo.ROOT_NODE_ID,
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
@@ -615,11 +667,13 @@ public class AccessibilityWindowManagerTest {
verify(mMockA11yEventSender, times(2))
.sendAccessibilityEventForCurrentUserLocked(captor.capture());
assertThat(captor.getAllValues().get(0),
- allOf(a11yWindowId(currentA11yFocusedWindowId),
+ allOf(displayId(initialDisplayId),
+ a11yWindowId(initialWindowId),
a11yWindowChanges(
AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
assertThat(captor.getAllValues().get(1),
- allOf(a11yWindowId(eventWindowId),
+ allOf(displayId(eventDisplayId),
+ a11yWindowId(eventWindowId),
a11yWindowChanges(
AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
}
@@ -674,10 +728,12 @@ public class AccessibilityWindowManagerTest {
verify(mMockA11yEventSender, times(2))
.sendAccessibilityEventForCurrentUserLocked(captor.capture());
assertThat(captor.getAllValues().get(0),
- allOf(a11yWindowId(eventWindowId),
+ allOf(displayId(Display.DEFAULT_DISPLAY),
+ a11yWindowId(eventWindowId),
a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
assertThat(captor.getAllValues().get(1),
- allOf(a11yWindowId(currentActiveWindowId),
+ allOf(displayId(Display.DEFAULT_DISPLAY),
+ a11yWindowId(currentActiveWindowId),
a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
}
@@ -861,6 +917,77 @@ public class AccessibilityWindowManagerTest {
assertTrue(TextUtils.equals(layoutParams.accessibilityTitle, a11yWindow.getTitle()));
}
+ @Test
+ public void sendAccessibilityEventOnWindowRemoval() {
+ final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+
+ // Removing index 0 because it's not focused, and avoids unnecessary layer change.
+ final int windowId =
+ getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
+ infos.remove(0);
+ for (WindowInfo info : infos) {
+ // Adjust layer number because it should start from 0.
+ info.layer--;
+ }
+
+ onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+
+ final ArgumentCaptor<AccessibilityEvent> captor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+ verify(mMockA11yEventSender, times(1))
+ .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+ assertThat(captor.getAllValues().get(0),
+ allOf(displayId(Display.DEFAULT_DISPLAY),
+ a11yWindowId(windowId),
+ a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_REMOVED)));
+ }
+
+ @Test
+ public void sendAccessibilityEventOnWindowAddition() throws RemoteException {
+ final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+
+ for (WindowInfo info : infos) {
+ // Adjust layer number because new window will have 0 so that layer number in
+ // A11yWindowInfo in window won't be changed.
+ info.layer++;
+ }
+
+ final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+ false, USER_SYSTEM_ID);
+ addWindowInfo(infos, token, 0);
+ final int windowId =
+ getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, infos.size() - 1);
+
+ onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+
+ final ArgumentCaptor<AccessibilityEvent> captor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+ verify(mMockA11yEventSender, times(1))
+ .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+ assertThat(captor.getAllValues().get(0),
+ allOf(displayId(Display.DEFAULT_DISPLAY),
+ a11yWindowId(windowId),
+ a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ADDED)));
+ }
+
+ @Test
+ public void sendAccessibilityEventOnWindowChange() {
+ final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+ infos.get(0).title = "new title";
+ final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
+
+ onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+
+ final ArgumentCaptor<AccessibilityEvent> captor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+ verify(mMockA11yEventSender, times(1))
+ .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+ assertThat(captor.getAllValues().get(0),
+ allOf(displayId(Display.DEFAULT_DISPLAY),
+ a11yWindowId(windowId),
+ a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_TITLE)));
+ }
+
private void registerLeashedTokenAndWindowId() {
mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID);
mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID);
@@ -1018,6 +1145,29 @@ public class AccessibilityWindowManagerTest {
}
}
+ static class DisplayIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+ private final int mDisplayId;
+
+ DisplayIdMatcher(int displayId) {
+ super();
+ mDisplayId = displayId;
+ }
+
+ static DisplayIdMatcher displayId(int displayId) {
+ return new DisplayIdMatcher(displayId);
+ }
+
+ @Override
+ protected boolean matchesSafely(AccessibilityEvent event) {
+ return event.getDisplayId() == mDisplayId;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("Matching to displayId " + mDisplayId);
+ }
+ }
+
static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
private int mWindowId;