Supporting windows updated per display [Part II]

Creating new class, DisplayWindowsObserver implementing
WindowManagerInternal.WindowsForAccessibilityCallback, receives
updated windows from window manager.

Bug: 132854721
Test: a11y CTS & unit tests
Test: atest AccessibilityWindowManagerTest
Change-Id: I211da59d72c284e4a87574d3fc1955f44036800a
This commit is contained in:
Jacky Kao
2019-07-23 11:46:48 +08:00
parent 3dd2c377c4
commit 3f730ebfd1
7 changed files with 854 additions and 625 deletions

View File

@@ -396,7 +396,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
return null;
}
AccessibilityWindowInfo window = mA11yWindowManager.findA11yWindowInfoById(windowId);
AccessibilityWindowInfo window =
mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId);
if (window != null) {
AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window);
windowClone.setConnectionId(mId);
@@ -1356,11 +1357,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
|| (action == ACTION_CLEAR_ACCESSIBILITY_FOCUS);
if (!isA11yFocusAction) {
final WindowInfo windowInfo =
mA11yWindowManager.findWindowInfoById(resolvedWindowId);
mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId);
if (windowInfo != null) activityToken = windowInfo.activityToken;
}
final AccessibilityWindowInfo a11yWindowInfo =
mA11yWindowManager.findA11yWindowInfoById(resolvedWindowId);
mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId);
if (a11yWindowInfo != null && a11yWindowInfo.isInPictureInPictureMode()
&& mA11yWindowManager.getPictureInPictureActionReplacingConnection() != null
&& !isA11yFocusAction) {
@@ -1413,11 +1414,13 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
int interactionId, int interrogatingPid, long interrogatingTid) {
final RemoteAccessibilityConnection pipActionReplacingConnection =
mA11yWindowManager.getPictureInPictureActionReplacingConnection();
final AccessibilityWindowInfo windowInfo =
mA11yWindowManager.findA11yWindowInfoById(resolvedWindowId);
if ((windowInfo == null) || !windowInfo.isInPictureInPictureMode()
synchronized (mLock) {
final AccessibilityWindowInfo windowInfo =
mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId);
if ((windowInfo == null) || !windowInfo.isInPictureInPictureMode()
|| (pipActionReplacingConnection == null)) {
return originalCallback;
return originalCallback;
}
}
return new ActionReplacingCallback(originalCallback,
pipActionReplacingConnection.getRemote(), interactionId,

View File

@@ -541,7 +541,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (event.getWindowId() ==
AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID) {
// The replacer window isn't shown to services. Move its events into the pip.
AccessibilityWindowInfo pip = mA11yWindowManager.getPictureInPictureWindow();
AccessibilityWindowInfo pip = mA11yWindowManager.getPictureInPictureWindowLocked();
if (pip != null) {
int pipId = pip.getId();
event.setWindowId(pipId);
@@ -770,7 +770,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (resolvedUserId != mCurrentUserId) {
return null;
}
if (mA11yWindowManager.findA11yWindowInfoById(windowId) == null) {
if (mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId) == null) {
return null;
}
return mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(userId, windowId);

View File

@@ -429,7 +429,7 @@ public class AccessibilitySecurityPolicy {
if (windowId == mAccessibilityWindowManager.getActiveWindowId(userId)) {
return true;
}
return mAccessibilityWindowManager.findA11yWindowInfoById(windowId) != null;
return mAccessibilityWindowManager.findA11yWindowInfoByIdLocked(windowId) != null;
}
private boolean isShellAllowedToRetrieveWindowLocked(int userId, int windowId) {

View File

@@ -179,9 +179,9 @@ public class AbstractAccessibilityServiceConnectionTest {
addA11yWindowInfo(mA11yWindowInfos, WINDOWID, false);
addA11yWindowInfo(mA11yWindowInfos, PIP_WINDOWID, true);
when(mMockA11yWindowManager.getWindowListLocked()).thenReturn(mA11yWindowInfos);
when(mMockA11yWindowManager.findA11yWindowInfoById(WINDOWID))
when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID))
.thenReturn(mA11yWindowInfos.get(0));
when(mMockA11yWindowManager.findA11yWindowInfoById(PIP_WINDOWID))
when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(PIP_WINDOWID))
.thenReturn(mA11yWindowInfos.get(1));
final RemoteAccessibilityConnection conn = getRemoteA11yConnection(
WINDOWID, mMockIA11yInteractionConnection, PACKAGE_NAME1);

View File

@@ -166,7 +166,7 @@ public class AccessibilitySecurityPolicyTest {
public void canDispatchAccessibilityEvent_otherEvents_windowIdExist_returnTrue() {
when(mMockA11yWindowManager.getActiveWindowId(UserHandle.USER_SYSTEM))
.thenReturn(WINDOWID2);
when(mMockA11yWindowManager.findA11yWindowInfoById(WINDOWID))
when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID))
.thenReturn(AccessibilityWindowInfo.obtain());
for (int i = 0; i < OTHER_EVENTS.length; i++) {
final AccessibilityEvent event = AccessibilityEvent.obtain(OTHER_EVENTS[i]);
@@ -287,7 +287,7 @@ public class AccessibilitySecurityPolicyTest {
.thenReturn(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
when(mMockA11yWindowManager.getActiveWindowId(UserHandle.USER_SYSTEM))
.thenReturn(WINDOWID2);
when(mMockA11yWindowManager.findA11yWindowInfoById(WINDOWID))
when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID))
.thenReturn(AccessibilityWindowInfo.obtain());
assertTrue(mA11ySecurityPolicy.canGetAccessibilityNodeInfoLocked(UserHandle.USER_SYSTEM,

View File

@@ -34,6 +34,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -53,6 +54,7 @@ import android.view.accessibility.IAccessibilityInteractionConnection;
import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
@@ -75,9 +77,12 @@ public class AccessibilityWindowManagerTest {
private static final boolean FORCE_SEND = true;
private static final boolean SEND_ON_WINDOW_CHANGES = false;
private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM;
// TO-DO [Multi-Display] : change the display count to 2
private static final int DISPLAY_COUNT = 1;
private static final int NUM_GLOBAL_WINDOWS = 4;
private static final int NUM_APP_WINDOWS = 4;
private static final int NUM_OF_WINDOWS = NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS;
private static final int NUM_OF_WINDOWS = (NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS)
* DISPLAY_COUNT;
private static final int DEFAULT_FOCUSED_INDEX = 1;
private static final int SCREEN_WIDTH = 1080;
private static final int SCREEN_HEIGHT = 1920;
@@ -86,7 +91,13 @@ public class AccessibilityWindowManagerTest {
// List of window token, mapping from windowId -> window token.
private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>();
private final ArrayList<WindowInfo> mWindowInfos = new ArrayList<>();
// List of window info lists, mapping from displayId -> window info lists.
private final SparseArray<ArrayList<WindowInfo>> mWindowInfos =
new SparseArray<>();
// List of callback, mapping from displayId -> callback.
private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows =
new SparseArray<>();
private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
@Mock private WindowManagerInternal mMockWindowManagerInternal;
@@ -109,29 +120,14 @@ public class AccessibilityWindowManagerTest {
mMockA11ySecurityPolicy,
mMockA11yUserManager);
// Add RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
// mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos
// for the test.
int layer = 0;
for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) {
final IWindow token = addAccessibilityInteractionConnection(true);
addWindowInfo(token, layer++);
for (int i = 0; i < DISPLAY_COUNT; i++) {
when(mMockWindowManagerInternal.setWindowsForAccessibilityCallback(eq(i), any()))
.thenReturn(true);
startTrackingPerDisplay(i);
}
for (int i = 0; i < NUM_APP_WINDOWS; i++) {
final IWindow token = addAccessibilityInteractionConnection(false);
addWindowInfo(token, layer++);
}
// setup default focus
mWindowInfos.get(DEFAULT_FOCUSED_INDEX).focused = true;
// Turn on windows tracking, and update window info
mA11yWindowManager.startTrackingWindows();
mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos);
assertEquals(mA11yWindowManager.getWindowListLocked().size(),
mWindowInfos.size());
// AccessibilityEventSender is invoked during onWindowsForAccessibilityChanged.
// Reset it for mockito verify of further test case.
// Resets it for mockito verify of further test case.
Mockito.reset(mMockA11yEventSender);
}
@@ -142,11 +138,12 @@ public class AccessibilityWindowManagerTest {
@Test
public void startTrackingWindows_shouldEnableWindowManagerCallback() {
// AccessibilityWindowManager#startTrackingWindows already invoked in setup
// AccessibilityWindowManager#startTrackingWindows already invoked in setup.
assertTrue(mA11yWindowManager.isTrackingWindowsLocked());
// TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY
final WindowsForAccessibilityCallback callbacks =
mCallbackOfWindows.get(Display.DEFAULT_DISPLAY);
verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
eq(Display.DEFAULT_DISPLAY), any());
eq(Display.DEFAULT_DISPLAY), eq(callbacks));
}
@Test
@@ -156,9 +153,9 @@ public class AccessibilityWindowManagerTest {
mA11yWindowManager.stopTrackingWindows();
assertFalse(mA11yWindowManager.isTrackingWindowsLocked());
// TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY
verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
eq(Display.DEFAULT_DISPLAY), any());
eq(Display.DEFAULT_DISPLAY), isNull());
}
@Test
@@ -177,87 +174,102 @@ public class AccessibilityWindowManagerTest {
@Test
public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX);
WindowInfo focusedWindowInfo =
mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked(
USER_SYSTEM_ID, focusedWindowInfo.token));
focusedWindowInfo.focused = false;
focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1);
focusedWindowInfo =
mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1);
focusedWindowInfo.focused = true;
mA11yWindowManager.onTouchInteractionStart();
mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
setTopFocusedWindowAndDisplay(Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX + 1);
onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
}
@Test
public void onWindowsChanged_shouldReportCorrectLayer() {
// AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup
List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
// AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
List<AccessibilityWindowInfo> a11yWindows =
mA11yWindowManager.getWindowListLocked();
for (int i = 0; i < a11yWindows.size(); i++) {
final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
final WindowInfo windowInfo = mWindowInfos.get(i);
assertThat(mWindowInfos.size() - windowInfo.layer - 1,
final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
assertThat(mWindowInfos.get(Display.DEFAULT_DISPLAY).size() - windowInfo.layer - 1,
is(a11yWindow.getLayer()));
}
}
@Test
public void onWindowsChanged_shouldReportCorrectOrder() {
// AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup
List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
// AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
List<AccessibilityWindowInfo> a11yWindows =
mA11yWindowManager.getWindowListLocked();
for (int i = 0; i < a11yWindows.size(); i++) {
final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
final IBinder windowToken = mA11yWindowManager
.getWindowTokenForUserAndWindowIdLocked(USER_SYSTEM_ID, a11yWindow.getId());
final WindowInfo windowInfo = mWindowInfos.get(i);
final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
assertThat(windowToken, is(windowInfo.token));
}
}
@Test
public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
final WindowInfo windowInfo = mWindowInfos.get(0);
final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer();
final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
final int correctLayer =
mA11yWindowManager.getWindowListLocked().get(0).getLayer();
windowInfo.layer += 1;
mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos);
assertNotEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer());
onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
assertNotEquals(correctLayer,
mA11yWindowManager.getWindowListLocked().get(0).getLayer());
}
@Test
public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() {
final WindowInfo windowInfo = mWindowInfos.get(0);
final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer();
final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
final int correctLayer =
mA11yWindowManager.getWindowListLocked().get(0).getLayer();
windowInfo.layer += 1;
mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
assertEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer());
onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
assertEquals(correctLayer,
mA11yWindowManager.getWindowListLocked().get(0).getLayer());
}
@Test
public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows()
throws RemoteException {
final AccessibilityWindowInfo oldWindow = mA11yWindowManager.getWindowListLocked().get(0);
final IWindow token = addAccessibilityInteractionConnection(true);
final AccessibilityWindowInfo oldWindow =
mA11yWindowManager.getWindowListLocked().get(0);
final IWindow token =
addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, true);
final WindowInfo windowInfo = WindowInfo.obtain();
windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
windowInfo.token = token.asBinder();
windowInfo.layer = 0;
windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
mWindowInfos.set(0, windowInfo);
mWindowInfos.get(Display.DEFAULT_DISPLAY).set(0, windowInfo);
mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
assertNotEquals(oldWindow, mA11yWindowManager.getWindowListLocked().get(0));
onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
assertNotEquals(oldWindow,
mA11yWindowManager.getWindowListLocked().get(0));
}
@Test
public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
final WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX);
final WindowInfo windowInfo = mWindowInfos.get(0);
final WindowInfo focusedWindowInfo =
mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
focusedWindowInfo.focused = false;
windowInfo.focused = true;
mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
assertTrue(mA11yWindowManager.getWindowListLocked().get(0).isFocused());
}
@@ -288,7 +300,8 @@ public class AccessibilityWindowManagerTest {
@Test
public void getWindowTokenForUserAndWindowId_shouldNotNull() {
final List<AccessibilityWindowInfo> windows = mA11yWindowManager.getWindowListLocked();
final List<AccessibilityWindowInfo> windows =
mA11yWindowManager.getWindowListLocked();
for (int i = 0; i < windows.size(); i++) {
final int windowId = windows.get(i).getId();
@@ -299,7 +312,8 @@ public class AccessibilityWindowManagerTest {
@Test
public void findWindowId() {
final List<AccessibilityWindowInfo> windows = mA11yWindowManager.getWindowListLocked();
final List<AccessibilityWindowInfo> windows =
mA11yWindowManager.getWindowListLocked();
for (int i = 0; i < windows.size(); i++) {
final int windowId = windows.get(i).getId();
final IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
@@ -313,13 +327,15 @@ public class AccessibilityWindowManagerTest {
@Test
public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() {
// Updates top 2 z-order WindowInfo are whole visible.
WindowInfo windowInfo = mWindowInfos.get(0);
WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
windowInfo = mWindowInfos.get(1);
windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT);
mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1);
windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2,
SCREEN_WIDTH, SCREEN_HEIGHT);
onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
final List<AccessibilityWindowInfo> a11yWindows =
mA11yWindowManager.getWindowListLocked();
final Region outBounds = new Region();
int windowId = a11yWindows.get(0).getId();
@@ -336,12 +352,13 @@ public class AccessibilityWindowManagerTest {
@Test
public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() {
// Updates z-order #1 WindowInfo is half visible
WindowInfo windowInfo = mWindowInfos.get(0);
// Updates z-order #1 WindowInfo is half visible.
WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
final List<AccessibilityWindowInfo> a11yWindows =
mA11yWindowManager.getWindowListLocked();
final Region outBounds = new Region();
int windowId = a11yWindows.get(1).getId();
@@ -353,7 +370,8 @@ public class AccessibilityWindowManagerTest {
@Test
public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() {
// Since z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible.
final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
final List<AccessibilityWindowInfo> a11yWindows =
mA11yWindowManager.getWindowListLocked();
final Region outBounds = new Region();
int windowId = a11yWindows.get(1).getId();
@@ -366,11 +384,12 @@ public class AccessibilityWindowManagerTest {
// Updates z-order #0 WindowInfo to have two interact-able areas.
Region region = new Region(0, 0, SCREEN_WIDTH, 200);
region.op(0, SCREEN_HEIGHT - 200, SCREEN_WIDTH, SCREEN_HEIGHT, Region.Op.UNION);
WindowInfo windowInfo = mWindowInfos.get(0);
WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
windowInfo.regionInScreen.set(region);
mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
final List<AccessibilityWindowInfo> a11yWindows =
mA11yWindowManager.getWindowListLocked();
final Region outBounds = new Region();
int windowId = a11yWindows.get(1).getId();
@@ -382,7 +401,8 @@ public class AccessibilityWindowManagerTest {
@Test
public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() {
final IBinder eventWindowToken = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1).token;
final IBinder eventWindowToken =
mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1).token;
final int eventWindowId = mA11yWindowManager.findWindowIdLocked(
USER_SYSTEM_ID, eventWindowToken);
when(mMockWindowManagerInternal.getFocusedWindowToken())
@@ -402,7 +422,8 @@ public class AccessibilityWindowManagerTest {
@Test
public void updateActiveAndA11yFocusedWindow_hoverEvent_touchInteract_shouldSetActiveWindow() {
final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX + 1);
final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
DEFAULT_FOCUSED_INDEX + 1);
final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
assertThat(currentActiveWindowId, is(not(eventWindowId)));
@@ -428,7 +449,8 @@ public class AccessibilityWindowManagerTest {
@Test
public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_shouldUpdateA11yFocus() {
final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX);
final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
DEFAULT_FOCUSED_INDEX);
final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
assertThat(currentA11yFocusedWindowId, is(not(eventWindowId)));
@@ -457,7 +479,8 @@ public class AccessibilityWindowManagerTest {
@Test
public void updateActiveAndA11yFocusedWindow_clearA11yFocusEvent_shouldClearA11yFocus() {
final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX);
final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
DEFAULT_FOCUSED_INDEX);
final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
assertThat(currentA11yFocusedWindowId, is(not(eventWindowId)));
@@ -482,7 +505,8 @@ public class AccessibilityWindowManagerTest {
@Test
public void onTouchInteractionEnd_shouldRollbackActiveWindow() {
final int eventWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX + 1);
final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
DEFAULT_FOCUSED_INDEX + 1);
final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
assertThat(currentActiveWindowId, is(not(eventWindowId)));
@@ -513,12 +537,14 @@ public class AccessibilityWindowManagerTest {
@Test
public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus()
throws RemoteException {
final IBinder defaultFocusWinToken = mWindowInfos.get(DEFAULT_FOCUSED_INDEX).token;
final IBinder defaultFocusWinToken =
mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).token;
final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked(
USER_SYSTEM_ID, defaultFocusWinToken);
when(mMockWindowManagerInternal.getFocusedWindowToken())
.thenReturn(defaultFocusWinToken);
final int newFocusWindowId = getWindowIdFromWindowInfos(DEFAULT_FOCUSED_INDEX + 1);
final int newFocusWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
DEFAULT_FOCUSED_INDEX + 1);
final IAccessibilityInteractionConnection mockNewFocusConnection =
mA11yWindowManager.getConnectionLocked(
USER_SYSTEM_ID, newFocusWindowId).getRemote();
@@ -556,28 +582,72 @@ public class AccessibilityWindowManagerTest {
@Test
public void getPictureInPictureWindow_shouldNotNull() {
assertNull(mA11yWindowManager.getPictureInPictureWindow());
mWindowInfos.get(1).inPictureInPicture = true;
mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
assertNull(mA11yWindowManager.getPictureInPictureWindowLocked());
mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1).inPictureInPicture = true;
onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
assertNotNull(mA11yWindowManager.getPictureInPictureWindow());
assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked());
}
@Test
public void notifyOutsideTouch() throws RemoteException {
final int targetWindowId = getWindowIdFromWindowInfos(1);
final int outsideWindowId = getWindowIdFromWindowInfos(0);
final int targetWindowId =
getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 1);
final int outsideWindowId =
getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
final IAccessibilityInteractionConnection mockRemoteConnection =
mA11yWindowManager.getConnectionLocked(
USER_SYSTEM_ID, outsideWindowId).getRemote();
mWindowInfos.get(0).hasFlagWatchOutsideTouch = true;
mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0).hasFlagWatchOutsideTouch = true;
onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
verify(mockRemoteConnection).notifyOutsideTouch();
}
private IWindow addAccessibilityInteractionConnection(boolean bGlobal)
private void startTrackingPerDisplay(int displayId) throws RemoteException {
ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>();
// Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
// mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos
// for the test.
int layer = 0;
for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) {
final IWindow token = addAccessibilityInteractionConnection(displayId, true);
addWindowInfo(windowInfosForDisplay, token, layer++);
}
for (int i = 0; i < NUM_APP_WINDOWS; i++) {
final IWindow token = addAccessibilityInteractionConnection(displayId, false);
addWindowInfo(windowInfosForDisplay, token, layer++);
}
// Setups default focus.
windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true;
// Turns on windows tracking, and update window info.
mA11yWindowManager.startTrackingWindows();
// Puts window lists into array.
mWindowInfos.put(displayId, windowInfosForDisplay);
// Sets the default display as the top focused display.
if (displayId == Display.DEFAULT_DISPLAY) {
setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX);
}
// Invokes callback for sending window lists to A11y framework.
onWindowsForAccessibilityChanged(displayId, FORCE_SEND);
assertEquals(mA11yWindowManager.getWindowListLocked().size(),
windowInfosForDisplay.size());
}
private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) {
ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor =
ArgumentCaptor.forClass(
WindowManagerInternal.WindowsForAccessibilityCallback.class);
verify(mMockWindowManagerInternal)
.setWindowsForAccessibilityCallback(eq(displayId),
windowsForAccessibilityCallbacksCaptor.capture());
return windowsForAccessibilityCallbacksCaptor.getValue();
}
private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal)
throws RemoteException {
final IWindow mockWindowToken = Mockito.mock(IWindow.class);
final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
@@ -588,6 +658,8 @@ public class AccessibilityWindowManagerTest {
when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(USER_SYSTEM_ID))
.thenReturn(bGlobal);
when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowToken.asBinder()))
.thenReturn(displayId);
int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
mockWindowToken, mockA11yConnection, PACKAGE_NAME, USER_SYSTEM_ID);
@@ -595,21 +667,40 @@ public class AccessibilityWindowManagerTest {
return mockWindowToken;
}
private void addWindowInfo(IWindow windowToken, int layer) {
private void addWindowInfo(ArrayList<WindowInfo> windowInfos, IWindow windowToken, int layer) {
final WindowInfo windowInfo = WindowInfo.obtain();
windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
windowInfo.token = windowToken.asBinder();
windowInfo.layer = layer;
windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
mWindowInfos.add(windowInfo);
windowInfos.add(windowInfo);
}
private int getWindowIdFromWindowInfos(int index) {
final IBinder windowToken = mWindowInfos.get(index).token;
private int getWindowIdFromWindowInfosForDisplay(int displayId, int index) {
final IBinder windowToken = mWindowInfos.get(displayId).get(index).token;
return mA11yWindowManager.findWindowIdLocked(
USER_SYSTEM_ID, windowToken);
}
private void setTopFocusedWindowAndDisplay(int displayId, int index) {
// Sets the top focus window.
final IBinder eventWindowToken = mWindowInfos.get(displayId).get(index).token;
when(mMockWindowManagerInternal.getFocusedWindowToken())
.thenReturn(eventWindowToken);
// Sets the top focused display.
when(mMockWindowManagerInternal.getDisplayIdForWindow(eventWindowToken))
.thenReturn(displayId);
}
private void onWindowsForAccessibilityChanged(int displayId, boolean forceSend) {
WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(displayId);
if (callbacks == null) {
callbacks = getWindowsForAccessibilityCallbacks(displayId);
mCallbackOfWindows.put(displayId, callbacks);
}
callbacks.onWindowsForAccessibilityChanged(forceSend, mWindowInfos.get(displayId));
}
static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
private int mWindowId;