diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 3743483377b5da7c7dc3e85897caec0208d586d4..37967fa86b0f74db22cf0162049778e854bb2d8d 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -85,6 +85,7 @@ android_test {
         "ravenwood-junit",
         "net_flags_lib",
         "CtsVirtualDeviceCommonLib",
+        "com_android_server_accessibility_flags_lib",
     ],
 
     libs: [
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 89d146da1b75384466ea729c71c9114fa604a4e6..8717a0500e574eb687e2e3f254670fa7a035b8ec 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -47,6 +47,9 @@ import android.os.IBinder;
 import android.os.LocaleList;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.IWindow;
@@ -67,6 +70,7 @@ import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
@@ -77,9 +81,16 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
+// This test verifies deprecated codepath. Probably changing this file means
+// AccessibilityWindowManagerWithAccessibilityWindowTest also needs to be updated.
+// LINT.IfChange
+
 /**
- * Tests for the AccessibilityWindowManager
+ * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y enabled.
+ * TODO(b/322444245): Merge with AccessibilityWindowManagerWithAccessibilityWindowTest
+ *  after completing the flag migration.
  */
+@RequiresFlagsDisabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y)
 public class AccessibilityWindowManagerTest {
     private static final String PACKAGE_NAME = "com.android.server.accessibility";
     private static final boolean FORCE_SEND = true;
@@ -132,6 +143,9 @@ public class AccessibilityWindowManagerTest {
     @Mock private IBinder mMockEmbeddedToken;
     @Mock private IBinder mMockInvalidToken;
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
     @Before
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
@@ -1227,3 +1241,4 @@ public class AccessibilityWindowManagerTest {
         }
     }
 }
+// LINT.ThenChange(/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java)
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4db27d272f8e84b9a056495f7504c7386a51db11
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
@@ -0,0 +1,1247 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_DEFAULT;
+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;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+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.doAnswer;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.Nullable;
+import android.graphics.Region;
+import android.os.IBinder;
+import android.os.LocaleList;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.IWindow;
+import android.view.WindowInfo;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityWindowAttributes;
+import android.view.accessibility.AccessibilityWindowInfo;
+import android.view.accessibility.IAccessibilityInteractionConnection;
+
+import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
+import com.android.server.accessibility.test.MessageCapturingHandler;
+import com.android.server.wm.WindowManagerInternal;
+import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
+
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y
+ * TODO(b/322444245): Merge with AccessibilityWindowManagerTest
+ *  after completing the flag migration.
+ */
+@RequiresFlagsEnabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y)
+public class AccessibilityWindowManagerWithAccessibilityWindowTest {
+    private static final String PACKAGE_NAME = "com.android.server.accessibility";
+    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;
+    private static final int USER_PROFILE = 11;
+    private static final int USER_PROFILE_PARENT = 1;
+    private static final int SECONDARY_DISPLAY_ID = Display.DEFAULT_DISPLAY + 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 DEFAULT_FOCUSED_INDEX = 1;
+    private static final int SCREEN_WIDTH = 1080;
+    private static final int SCREEN_HEIGHT = 1920;
+    private static final int INVALID_ID = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+    private static final int HOST_WINDOW_ID = 10;
+    private static final int EMBEDDED_WINDOW_ID = 11;
+    private static final int OTHER_WINDOW_ID = 12;
+
+    private AccessibilityWindowManager mA11yWindowManager;
+    // Window manager will support multiple focused window if config_perDisplayFocusEnabled is true,
+    // i.e., each display would have its current focused window, and one of all focused windows
+    // would be top focused window. Otherwise, window manager only supports one focused window
+    // at all displays, and that focused window would be top focused window.
+    private boolean mSupportPerDisplayFocus = false;
+    private int mTopFocusedDisplayId = Display.INVALID_DISPLAY;
+    private IBinder mTopFocusedWindowToken = null;
+
+    // List of window token, mapping from windowId -> window token.
+    private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>();
+    // 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<>();
+    // List of display ID.
+    private final ArrayList<Integer> mExpectedDisplayList = new ArrayList<>(Arrays.asList(
+            Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID));
+
+    private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
+
+    @Mock
+    private WindowManagerInternal mMockWindowManagerInternal;
+    @Mock
+    private AccessibilityWindowManager.AccessibilityEventSender mMockA11yEventSender;
+    @Mock
+    private AccessibilitySecurityPolicy mMockA11ySecurityPolicy;
+    @Mock
+    private AccessibilitySecurityPolicy.AccessibilityUserManager mMockA11yUserManager;
+    @Mock
+    private AccessibilityTraceManager mMockA11yTraceManager;
+
+    @Mock
+    private IBinder mMockHostToken;
+    @Mock
+    private IBinder mMockEmbeddedToken;
+    @Mock
+    private IBinder mMockInvalidToken;
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    @Before
+    public void setUp() throws RemoteException {
+        MockitoAnnotations.initMocks(this);
+        when(mMockA11yUserManager.getCurrentUserIdLocked()).thenReturn(USER_SYSTEM_ID);
+        when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
+                USER_PROFILE)).thenReturn(USER_PROFILE_PARENT);
+        when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
+                USER_SYSTEM_ID)).thenReturn(USER_SYSTEM_ID);
+        when(mMockA11ySecurityPolicy.resolveValidReportedPackageLocked(
+                anyString(), anyInt(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME);
+
+        doAnswer((invocation) -> {
+            onWindowsForAccessibilityChanged(invocation.getArgument(0), false);
+            return null;
+        }).when(mMockWindowManagerInternal).computeWindowsForAccessibility(anyInt());
+
+        mA11yWindowManager = new AccessibilityWindowManager(new Object(), mHandler,
+                mMockWindowManagerInternal,
+                mMockA11yEventSender,
+                mMockA11ySecurityPolicy,
+                mMockA11yUserManager,
+                mMockA11yTraceManager);
+        // Starts tracking window of default display and sets the default display
+        // as top focused display before each testing starts.
+        startTrackingPerDisplay(Display.DEFAULT_DISPLAY);
+
+        // AccessibilityEventSender is invoked during onWindowsForAccessibilityChanged.
+        // Resets it for mockito verify of further test case.
+        Mockito.reset(mMockA11yEventSender);
+
+        registerLeashedTokenAndWindowId();
+    }
+
+    @After
+    public void tearDown() {
+        mHandler.removeAllMessages();
+    }
+
+    @Test
+    public void startTrackingWindows_shouldEnableWindowManagerCallback() {
+        // AccessibilityWindowManager#startTrackingWindows already invoked in setup.
+        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
+        final WindowsForAccessibilityCallback callbacks =
+                mCallbackOfWindows.get(Display.DEFAULT_DISPLAY);
+        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
+                eq(Display.DEFAULT_DISPLAY), eq(callbacks));
+    }
+
+    @Test
+    public void stopTrackingWindows_shouldDisableWindowManagerCallback() {
+        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
+        Mockito.reset(mMockWindowManagerInternal);
+
+        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
+        assertFalse(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
+        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
+                eq(Display.DEFAULT_DISPLAY), isNull());
+
+    }
+
+    @Test
+    public void stopTrackingWindows_shouldClearWindows() {
+        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
+        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+
+        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
+        assertNull(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY));
+        assertEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
+                AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
+        assertEquals(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID),
+                activeWindowId);
+    }
+
+    @Test
+    public void stopTrackingWindows_onNonTopFocusedDisplay_shouldNotResetTopFocusWindow()
+            throws RemoteException {
+        // At setup, the default display sets be the top focused display and
+        // its current focused window sets be the top focused window.
+        // Starts tracking window of second display.
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
+        // Stops tracking windows of second display.
+        mA11yWindowManager.stopTrackingWindows(SECONDARY_DISPLAY_ID);
+        assertNotEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
+                AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
+    }
+
+    @Test
+    public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
+        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        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(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1);
+        focusedWindowInfo.focused = true;
+
+        mA11yWindowManager.onTouchInteractionStart();
+        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_focusChangeOnNonTopFocusedDisplay_perDisplayFocusOn_notChangeWindow()
+            throws RemoteException {
+        // At setup, the default display sets be the top focused display and
+        // its current focused window sets be the top focused window.
+        // Sets supporting multiple focused window, i.e., config_perDisplayFocusEnabled is true.
+        mSupportPerDisplayFocus = true;
+        // Starts tracking window of second display.
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+        // Gets the active window.
+        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        // Gets the top focused window.
+        final int topFocusedWindowId =
+                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT);
+        // Changes the current focused window at second display.
+        changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
+                DEFAULT_FOCUSED_INDEX + 1, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
+
+        onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
+        // The active window should not be changed.
+        assertEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
+        // The top focused window should not be changed.
+        assertEquals(topFocusedWindowId,
+                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT));
+    }
+
+    @Test
+    public void
+            onWindowChange_focusChangeToNonTopFocusedDisplay_perDisplayFocusOff_shouldChangeWindow()
+            throws RemoteException {
+        // At setup, the default display sets be the top focused display and
+        // its current focused window sets be the top focused window.
+        // Sets not supporting multiple focused window, i.e., config_perDisplayFocusEnabled is
+        // false.
+        mSupportPerDisplayFocus = false;
+        // Starts tracking window of second display.
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+        // Gets the active window.
+        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        // Gets the top focused window.
+        final int topFocusedWindowId =
+                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT);
+        // Changes the current focused window from default display to second display.
+        changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
+                DEFAULT_FOCUSED_INDEX, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
+        // The active window should be changed.
+        assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
+        // The top focused window should be changed.
+        assertNotEquals(topFocusedWindowId,
+                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT));
+    }
+
+    @Test
+    public void onWindowsChanged_shouldReportCorrectLayer() {
+        // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
+        List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        for (int i = 0; i < a11yWindows.size(); i++) {
+            final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
+            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(Display.DEFAULT_DISPLAY);
+        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(Display.DEFAULT_DISPLAY).get(i);
+            assertThat(windowToken, is(windowInfo.token));
+        }
+    }
+
+    @Test
+    public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
+        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        final int correctLayer =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer();
+        windowInfo.layer += 1;
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+        assertNotEquals(correctLayer,
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer());
+    }
+
+    @Test
+    public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() {
+        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        final int correctLayer =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer();
+        windowInfo.layer += 1;
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        assertEquals(correctLayer,
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer());
+    }
+
+    @Test
+    public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows()
+            throws RemoteException {
+        final AccessibilityWindowInfo oldWindow =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0);
+        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                true, USER_SYSTEM_ID);
+        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.get(Display.DEFAULT_DISPLAY).set(0, windowInfo);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        assertNotEquals(oldWindow,
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0));
+    }
+
+    @Test
+    public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
+        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;
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        assertTrue(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0)
+                .isFocused());
+    }
+
+    @Test
+    public void removeAccessibilityInteractionConnection_byWindowToken_shouldRemoved() {
+        for (int i = 0; i < NUM_OF_WINDOWS; i++) {
+            final int windowId = mA11yWindowTokens.keyAt(i);
+            final IWindow windowToken = mA11yWindowTokens.valueAt(i);
+            assertNotNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
+
+            mA11yWindowManager.removeAccessibilityInteractionConnection(windowToken);
+            assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
+        }
+    }
+
+    @Test
+    public void remoteAccessibilityConnection_binderDied_shouldRemoveConnection() {
+        for (int i = 0; i < NUM_OF_WINDOWS; i++) {
+            final int windowId = mA11yWindowTokens.keyAt(i);
+            final RemoteAccessibilityConnection remoteA11yConnection =
+                    mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId);
+            assertNotNull(remoteA11yConnection);
+
+            remoteA11yConnection.binderDied();
+            assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
+        }
+    }
+
+    @Test
+    public void getWindowTokenForUserAndWindowId_shouldNotNull() {
+        final List<AccessibilityWindowInfo> windows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        for (int i = 0; i < windows.size(); i++) {
+            final int windowId = windows.get(i).getId();
+
+            assertNotNull(mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
+                    USER_SYSTEM_ID, windowId));
+        }
+    }
+
+    @Test
+    public void findWindowId() {
+        final List<AccessibilityWindowInfo> windows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        for (int i = 0; i < windows.size(); i++) {
+            final int windowId = windows.get(i).getId();
+            final IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
+                    USER_SYSTEM_ID, windowId);
+
+            assertEquals(mA11yWindowManager.findWindowIdLocked(
+                    USER_SYSTEM_ID, windowToken), windowId);
+        }
+    }
+
+    @Test
+    public void resolveParentWindowId_windowIsNotEmbedded_shouldReturnGivenId()
+            throws RemoteException {
+        final int windowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, false,
+                Mockito.mock(IBinder.class), USER_SYSTEM_ID);
+        assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId));
+    }
+
+    @Test
+    public void resolveParentWindowId_windowIsNotRegistered_shouldReturnGivenId() {
+        final int windowId = -1;
+        assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId));
+    }
+
+    @Test
+    public void resolveParentWindowId_windowIsAssociated_shouldReturnParentWindowId()
+            throws RemoteException {
+        final IBinder mockHostToken = Mockito.mock(IBinder.class);
+        final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class);
+        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, mockHostToken, USER_SYSTEM_ID);
+        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, mockEmbeddedToken, USER_SYSTEM_ID);
+
+        mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken);
+
+        final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
+                embeddedWindowId);
+        assertEquals(hostWindowId, resolvedWindowId);
+    }
+
+    @Test
+    public void resolveParentWindowId_windowIsDisassociated_shouldReturnGivenId()
+            throws RemoteException {
+        final IBinder mockHostToken = Mockito.mock(IBinder.class);
+        final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class);
+        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, mockHostToken, USER_SYSTEM_ID);
+        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, mockEmbeddedToken, USER_SYSTEM_ID);
+
+        mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken);
+        mA11yWindowManager.disassociateEmbeddedHierarchyLocked(mockEmbeddedToken);
+
+        final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
+                embeddedWindowId);
+        assertNotEquals(hostWindowId, resolvedWindowId);
+        assertEquals(embeddedWindowId, resolvedWindowId);
+    }
+
+    @Test
+    public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() {
+        // Updates top 2 z-order WindowInfo are whole visible.
+        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
+        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(Display.DEFAULT_DISPLAY);
+        final Region outBounds = new Region();
+        int windowId = a11yWindows.get(0).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
+        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
+
+        windowId = a11yWindows.get(1).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
+        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
+    }
+
+    @Test
+    public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() {
+        // 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);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        final Region outBounds = new Region();
+        int windowId = a11yWindows.get(1).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
+        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
+    }
+
+    @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(Display.DEFAULT_DISPLAY);
+        final Region outBounds = new Region();
+        int windowId = a11yWindows.get(1).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertTrue(outBounds.getBounds().isEmpty());
+    }
+
+    @Test
+    public void computePartialInteractiveRegionForWindow_partialVisible_returnVisibleRegion() {
+        // 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(Display.DEFAULT_DISPLAY).get(0);
+        windowInfo.regionInScreen.set(region);
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        final Region outBounds = new Region();
+        int windowId = a11yWindows.get(1).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertFalse(outBounds.getBounds().isEmpty());
+        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
+        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT - 400));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() {
+        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.getFocusedWindowTokenFromWindowStates())
+                .thenReturn(eventWindowToken);
+
+        final int noUse = 0;
+        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
+        assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
+                is(eventWindowId));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_hoverEvent_touchInteract_shouldSetActiveWindow() {
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX + 1);
+        final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        assertThat(currentActiveWindowId, is(not(eventWindowId)));
+
+        final int noUse = 0;
+        mA11yWindowManager.onTouchInteractionStart();
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(2))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(currentActiveWindowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
+        assertThat(captor.getAllValues().get(1),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(eventWindowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_shouldUpdateA11yFocus() {
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX);
+        final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
+        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,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(2))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(initialDisplayId),
+                        a11yWindowId(initialWindowId),
+                        a11yWindowChanges(
+                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
+        assertThat(captor.getAllValues().get(1),
+                allOf(displayId(eventDisplayId),
+                        a11yWindowId(eventWindowId),
+                        a11yWindowChanges(
+                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_clearA11yFocusEvent_shouldClearA11yFocus() {
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX);
+        final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
+        assertThat(currentA11yFocusedWindowId, is(not(eventWindowId)));
+
+        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));
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                        AccessibilityNodeInfo.FOCUS_ACCESSIBILITY),
+                is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
+    }
+
+    @Test
+    public void onTouchInteractionEnd_shouldRollbackActiveWindow() {
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX + 1);
+        final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        assertThat(currentActiveWindowId, is(not(eventWindowId)));
+
+        final int noUse = 0;
+        mA11yWindowManager.onTouchInteractionStart();
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
+        // AccessibilityEventSender is invoked after active window changed. Reset it.
+        Mockito.reset(mMockA11yEventSender);
+
+        mA11yWindowManager.onTouchInteractionEnd();
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(2))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(eventWindowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
+        assertThat(captor.getAllValues().get(1),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(currentActiveWindowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
+    }
+
+    @Test
+    public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus()
+            throws RemoteException {
+        final IBinder defaultFocusWinToken =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).token;
+        final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, defaultFocusWinToken);
+        when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
+                .thenReturn(defaultFocusWinToken);
+        final int newFocusWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX + 1);
+        final IAccessibilityInteractionConnection mockNewFocusConnection =
+                mA11yWindowManager.getConnectionLocked(
+                        USER_SYSTEM_ID, newFocusWindowId).getRemote();
+
+        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
+        final int noUse = 0;
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                defaultFocusWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(defaultFocusWindowId));
+        assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
+                is(defaultFocusWindowId));
+
+        mA11yWindowManager.onTouchInteractionStart();
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                newFocusWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
+                noUse);
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                newFocusWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(newFocusWindowId));
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(newFocusWindowId));
+
+        mA11yWindowManager.onTouchInteractionEnd();
+        mHandler.sendLastMessage();
+        verify(mockNewFocusConnection).clearAccessibilityFocus();
+    }
+
+    @Test
+    public void getPictureInPictureWindow_shouldNotNull() {
+        assertNull(mA11yWindowManager.getPictureInPictureWindowLocked());
+        mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1).inPictureInPicture = true;
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked());
+    }
+
+    @Test
+    public void notifyOutsideTouch() throws RemoteException {
+        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(Display.DEFAULT_DISPLAY).get(0).hasFlagWatchOutsideTouch = true;
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
+        verify(mockRemoteConnection).notifyOutsideTouch();
+    }
+
+    @Test
+    public void addAccessibilityInteractionConnection_profileUser_findInParentUser()
+            throws RemoteException {
+        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, USER_PROFILE);
+        final int windowId = mA11yWindowManager.findWindowIdLocked(
+                USER_PROFILE_PARENT, token.asBinder());
+        assertTrue(windowId >= 0);
+    }
+
+    @Test
+    public void getDisplayList() throws RemoteException {
+        // Starts tracking window of second display.
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+
+        final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked(
+                DISPLAY_TYPE_DEFAULT);
+        assertTrue(displayList.equals(mExpectedDisplayList));
+    }
+
+    @Test
+    public void setAccessibilityWindowIdToSurfaceMetadata()
+            throws RemoteException {
+        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                true, USER_SYSTEM_ID);
+        int windowId = -1;
+        for (int i = 0; i < mA11yWindowTokens.size(); i++) {
+            if (mA11yWindowTokens.valueAt(i).equals(token)) {
+                windowId = mA11yWindowTokens.keyAt(i);
+            }
+        }
+        assertNotEquals("Returned token is not found in mA11yWindowTokens", -1, windowId);
+        verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
+                token.asBinder(), windowId);
+
+        mA11yWindowManager.removeAccessibilityInteractionConnection(token);
+        verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
+                token.asBinder(), -1);
+    }
+
+    @Test
+    public void getHostTokenLocked_hierarchiesAreAssociated_shouldReturnHostToken() {
+        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
+        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
+        assertEquals(hostToken, mMockHostToken);
+    }
+
+    @Test
+    public void getHostTokenLocked_hierarchiesAreNotAssociated_shouldReturnNull() {
+        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
+        assertNull(hostToken);
+    }
+
+    @Test
+    public void getHostTokenLocked_embeddedHierarchiesAreDisassociated_shouldReturnNull() {
+        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
+        mA11yWindowManager.disassociateLocked(mMockEmbeddedToken);
+        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
+        assertNull(hostToken);
+    }
+
+    @Test
+    public void getHostTokenLocked_hostHierarchiesAreDisassociated_shouldReturnNull() {
+        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
+        mA11yWindowManager.disassociateLocked(mMockHostToken);
+        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockHostToken);
+        assertNull(hostToken);
+    }
+
+    @Test
+    public void getWindowIdLocked_windowIsRegistered_shouldReturnWindowId() {
+        final int windowId = mA11yWindowManager.getWindowIdLocked(mMockHostToken);
+        assertEquals(windowId, HOST_WINDOW_ID);
+    }
+
+    @Test
+    public void getWindowIdLocked_windowIsNotRegistered_shouldReturnInvalidWindowId() {
+        final int windowId = mA11yWindowManager.getWindowIdLocked(mMockInvalidToken);
+        assertEquals(windowId, INVALID_ID);
+    }
+
+    @Test
+    public void getTokenLocked_windowIsRegistered_shouldReturnToken() {
+        final IBinder token = mA11yWindowManager.getLeashTokenLocked(HOST_WINDOW_ID);
+        assertEquals(token, mMockHostToken);
+    }
+
+    @Test
+    public void getTokenLocked_windowIsNotRegistered_shouldReturnNull() {
+        final IBinder token = mA11yWindowManager.getLeashTokenLocked(OTHER_WINDOW_ID);
+        assertNull(token);
+    }
+
+    @Test
+    public void setAccessibilityWindowAttributes_windowIsNotRegistered_titleIsChanged() {
+        final int windowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
+        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+        layoutParams.accessibilityTitle = "accessibility window title";
+        final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes(
+                layoutParams, new LocaleList());
+
+        mA11yWindowManager.setAccessibilityWindowAttributes(Display.DEFAULT_DISPLAY, windowId,
+                USER_SYSTEM_ID, attributes);
+
+        final AccessibilityWindowInfo a11yWindow = mA11yWindowManager.findA11yWindowInfoByIdLocked(
+                windowId);
+        assertEquals(toString(layoutParams.accessibilityTitle), toString(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);
+    }
+
+    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, USER_SYSTEM_ID);
+            addWindowInfo(windowInfosForDisplay, token, layer++);
+
+        }
+        for (int i = 0; i < NUM_APP_WINDOWS; i++) {
+            final IWindow token = addAccessibilityInteractionConnection(displayId,
+                    false, USER_SYSTEM_ID);
+            addWindowInfo(windowInfosForDisplay, token, layer++);
+        }
+        // Sets up current focused window of display.
+        // Each display has its own current focused window if config_perDisplayFocusEnabled is true.
+        // Otherwise only default display needs to current focused window.
+        if (mSupportPerDisplayFocus || displayId == Display.DEFAULT_DISPLAY) {
+            windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true;
+        }
+        // Turns on windows tracking, and update window info.
+        mA11yWindowManager.startTrackingWindows(displayId, false);
+        // Puts window lists into array.
+        mWindowInfos.put(displayId, windowInfosForDisplay);
+        // Sets the default display is the top focused display and
+        // its current focused window is the top focused window.
+        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(displayId).size(),
+                windowInfosForDisplay.size());
+    }
+
+    private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) {
+        ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor =
+                ArgumentCaptor.forClass(
+                        WindowsForAccessibilityCallback.class);
+        verify(mMockWindowManagerInternal)
+                .setWindowsForAccessibilityCallback(eq(displayId),
+                        windowsForAccessibilityCallbacksCaptor.capture());
+        return windowsForAccessibilityCallbacksCaptor.getValue();
+    }
+
+    private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal,
+            int userId) throws RemoteException {
+        final IWindow mockWindowToken = Mockito.mock(IWindow.class);
+        final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
+                IAccessibilityInteractionConnection.class);
+        final IBinder mockConnectionBinder = Mockito.mock(IBinder.class);
+        final IBinder mockWindowBinder = Mockito.mock(IBinder.class);
+        final IBinder mockLeashToken = Mockito.mock(IBinder.class);
+        when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder);
+        when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
+        when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId))
+                .thenReturn(bGlobal);
+        when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder))
+                .thenReturn(displayId);
+
+        int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
+                mockWindowToken, mockLeashToken, mockA11yConnection, PACKAGE_NAME, userId);
+        mA11yWindowTokens.put(windowId, mockWindowToken);
+        return mockWindowToken;
+    }
+
+    private int addAccessibilityInteractionConnection(int displayId, boolean bGlobal,
+            IBinder leashToken, int userId) throws RemoteException {
+        final IWindow mockWindowToken = Mockito.mock(IWindow.class);
+        final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
+                IAccessibilityInteractionConnection.class);
+        final IBinder mockConnectionBinder = Mockito.mock(IBinder.class);
+        final IBinder mockWindowBinder = Mockito.mock(IBinder.class);
+        when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder);
+        when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
+        when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId))
+                .thenReturn(bGlobal);
+        when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder))
+                .thenReturn(displayId);
+
+        int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
+                mockWindowToken, leashToken, mockA11yConnection, PACKAGE_NAME, userId);
+        mA11yWindowTokens.put(windowId, mockWindowToken);
+        return windowId;
+    }
+
+    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);
+        windowInfos.add(windowInfo);
+    }
+
+    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.
+        mTopFocusedWindowToken = mWindowInfos.get(displayId).get(index).token;
+        // Sets the top focused display.
+        mTopFocusedDisplayId = 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, mTopFocusedDisplayId,
+                mTopFocusedWindowToken, mWindowInfos.get(displayId));
+    }
+
+    private void changeFocusedWindowOnDisplayPerDisplayFocusConfig(
+            int changeFocusedDisplayId, int newFocusedWindowIndex, int oldTopFocusedDisplayId,
+            int oldFocusedWindowIndex) {
+        if (mSupportPerDisplayFocus) {
+            // Gets the old focused window of display which wants to change focused window.
+            WindowInfo focusedWindowInfo =
+                    mWindowInfos.get(changeFocusedDisplayId).get(oldFocusedWindowIndex);
+            // Resets the focus of old focused window.
+            focusedWindowInfo.focused = false;
+            // Gets the new window of display which wants to change focused window.
+            focusedWindowInfo =
+                    mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex);
+            // Sets the focus of new focused window.
+            focusedWindowInfo.focused = true;
+        } else {
+            // Gets the window of display which wants to change focused window.
+            WindowInfo focusedWindowInfo =
+                    mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex);
+            // Sets the focus of new focused window.
+            focusedWindowInfo.focused = true;
+            // Gets the old focused window of old top focused display.
+            focusedWindowInfo =
+                    mWindowInfos.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex);
+            // Resets the focus of old focused window.
+            focusedWindowInfo.focused = false;
+            // Changes the top focused display and window.
+            setTopFocusedWindowAndDisplay(changeFocusedDisplayId, newFocusedWindowIndex);
+        }
+    }
+
+    @Nullable
+    private static String toString(@Nullable CharSequence cs) {
+        return cs == null ? null : cs.toString();
+    }
+
+    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;
+
+        WindowIdMatcher(int windowId) {
+            super();
+            mWindowId = windowId;
+        }
+
+        static WindowIdMatcher a11yWindowId(int windowId) {
+            return new WindowIdMatcher(windowId);
+        }
+
+        @Override
+        protected boolean matchesSafely(AccessibilityEvent event) {
+            return event.getWindowId() == mWindowId;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Matching to windowId " + mWindowId);
+        }
+    }
+
+    static class WindowChangesMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+        private int mWindowChanges;
+
+        WindowChangesMatcher(int windowChanges) {
+            super();
+            mWindowChanges = windowChanges;
+        }
+
+        static WindowChangesMatcher a11yWindowChanges(int windowChanges) {
+            return new WindowChangesMatcher(windowChanges);
+        }
+
+        @Override
+        protected boolean matchesSafely(AccessibilityEvent event) {
+            return event.getWindowChanges() == mWindowChanges;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Matching to window changes " + mWindowChanges);
+        }
+    }
+}