From e6014fc060e51f6950bf5ae9573a1d92d5c7bb94 Mon Sep 17 00:00:00 2001 From: Jacky Kao Date: Thu, 10 Jun 2021 09:23:20 +0800 Subject: [PATCH] Reset the features in A11yInputFilter per display The A11yInputFilter is an input filter for implementing many accessibility features on multi-display. When any display is added or removed, all features of all displays would be reset now. To avoid server side bad user experience, we should only reset the features and the event stream state based on the changed display which is added or removed. Bug: 187996964 Test: a11y CTS & unit tests Change-Id: I39ae59e12690240adbb0e81338dcb4c736a92197 --- .../AccessibilityInputFilter.java | 324 +++++++++++------- .../AccessibilityManagerService.java | 7 +- .../AccessibilityInputFilterTest.java | 113 +++++- 3 files changed, 315 insertions(+), 129 deletions(-) diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index bae2e1ac42aee..7d2b71f7852b9 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -21,6 +21,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY import android.accessibilityservice.AccessibilityTrace; import android.annotation.MainThread; +import android.annotation.NonNull; import android.content.Context; import android.graphics.Region; import android.os.PowerManager; @@ -44,7 +45,10 @@ import com.android.server.accessibility.magnification.WindowMagnificationGesture import com.android.server.accessibility.magnification.WindowMagnificationPromptController; import com.android.server.policy.WindowManagerPolicy; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.ArrayList; +import java.util.StringJoiner; /** * This class is an input filter for implementing accessibility features such @@ -172,9 +176,9 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo private int mEnabledFeatures; - private EventStreamState mMouseStreamState; + private final SparseArray mMouseStreamStates = new SparseArray<>(0); - private EventStreamState mTouchScreenStreamState; + private final SparseArray mTouchScreenStreamStates = new SparseArray<>(0); private EventStreamState mKeyboardStreamState; @@ -212,10 +216,17 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo super.onUninstalled(); } - void onDisplayChanged() { + void onDisplayAdded(@NonNull Display display) { if (mInstalled) { - disableFeatures(); - enableFeatures(); + resetStreamStateForDisplay(display.getDisplayId()); + enableFeaturesForDisplay(display); + } + } + + void onDisplayRemoved(int displayId) { + if (mInstalled) { + disableFeaturesForDisplay(displayId); + resetStreamStateForDisplay(displayId); } } @@ -243,16 +254,17 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo return; } - int eventSource = event.getSource(); + final int eventSource = event.getSource(); + final int displayId = event.getDisplayId(); if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) { state.reset(); - clearEventsForAllEventHandlers(eventSource); + clearEventStreamHandler(displayId, eventSource); super.onInputEvent(event, policyFlags); return; } if (state.updateInputSource(event.getSource())) { - clearEventsForAllEventHandlers(eventSource); + clearEventStreamHandler(displayId, eventSource); } if (!state.inputSourceValid()) { @@ -281,35 +293,39 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo */ private EventStreamState getEventStreamState(InputEvent event) { if (event instanceof MotionEvent) { - if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) { - if (mTouchScreenStreamState == null) { - mTouchScreenStreamState = new TouchScreenEventStreamState(); - } - return mTouchScreenStreamState; - } - if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { - if (mMouseStreamState == null) { - mMouseStreamState = new MouseEventStreamState(); - } - return mMouseStreamState; - } + final int displayId = event.getDisplayId(); + + if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) { + EventStreamState touchScreenStreamState = mTouchScreenStreamStates.get(displayId); + if (touchScreenStreamState == null) { + touchScreenStreamState = new TouchScreenEventStreamState(); + mTouchScreenStreamStates.put(displayId, touchScreenStreamState); + } + return touchScreenStreamState; + } + if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { + EventStreamState mouseStreamState = mMouseStreamStates.get(displayId); + if (mouseStreamState == null) { + mouseStreamState = new MouseEventStreamState(); + mMouseStreamStates.put(displayId, mouseStreamState); + } + return mouseStreamState; + } } else if (event instanceof KeyEvent) { - if (event.isFromSource(InputDevice.SOURCE_KEYBOARD)) { - if (mKeyboardStreamState == null) { - mKeyboardStreamState = new KeyboardEventStreamState(); - } - return mKeyboardStreamState; - } + if (event.isFromSource(InputDevice.SOURCE_KEYBOARD)) { + if (mKeyboardStreamState == null) { + mKeyboardStreamState = new KeyboardEventStreamState(); + } + return mKeyboardStreamState; + } } return null; } - private void clearEventsForAllEventHandlers(int eventSource) { - for (int i = 0; i < mEventHandler.size(); i++) { - final EventStreamTransformation eventHandler = mEventHandler.valueAt(i); - if (eventHandler != null) { - eventHandler.clearEvents(eventSource); - } + private void clearEventStreamHandler(int displayId, int eventSource) { + final EventStreamTransformation eventHandler = mEventHandler.get(displayId); + if (eventHandler != null) { + eventHandler.clearEvents(eventSource); } } @@ -425,56 +441,69 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo private void enableFeatures() { if (DEBUG) Slog.i(TAG, "enableFeatures()"); - resetStreamState(); + resetAllStreamState(); final ArrayList displaysList = mAms.getValidDisplayList(); - if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) { - mAutoclickController = new AutoclickController( - mContext, mUserId, mAms.getTraceManager()); - addFirstEventHandlerForAllDisplays(displaysList, mAutoclickController); - } - for (int i = displaysList.size() - 1; i >= 0; i--) { - final int displayId = displaysList.get(i).getDisplayId(); - final Context displayContext = mContext.createDisplayContext(displaysList.get(i)); + enableFeaturesForDisplay(displaysList.get(i)); + } + enableDisplayIndependentFeatures(); + } - if ((mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) { - TouchExplorer explorer = new TouchExplorer(displayContext, mAms); - if ((mEnabledFeatures & FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0) { - explorer.setServiceHandlesDoubleTap(true); - } - if ((mEnabledFeatures & FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0) { - explorer.setMultiFingerGesturesEnabled(true); - } - if ((mEnabledFeatures & FLAG_REQUEST_2_FINGER_PASSTHROUGH) != 0) { - explorer.setTwoFingerPassthroughEnabled(true); - } - if ((mEnabledFeatures & FLAG_SEND_MOTION_EVENTS) != 0) { - explorer.setSendMotionEventsEnabled(true); - } - addFirstEventHandler(displayId, explorer); - mTouchExplorer.put(displayId, explorer); - } - - if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0 - || ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) - || ((mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0)) { - final MagnificationGestureHandler magnificationGestureHandler = - createMagnificationGestureHandler(displayId, - displayContext); - addFirstEventHandler(displayId, magnificationGestureHandler); - mMagnificationGestureHandler.put(displayId, magnificationGestureHandler); - } - - if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) { - MotionEventInjector injector = new MotionEventInjector( - mContext.getMainLooper(), mAms.getTraceManager()); - addFirstEventHandler(displayId, injector); - mMotionEventInjectors.put(displayId, injector); - } + private void enableFeaturesForDisplay(Display display) { + if (DEBUG) { + Slog.i(TAG, "enableFeaturesForDisplay() : display Id = " + display.getDisplayId()); } + final Context displayContext = mContext.createDisplayContext(display); + final int displayId = display.getDisplayId(); + + if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) { + if (mAutoclickController == null) { + mAutoclickController = new AutoclickController( + mContext, mUserId, mAms.getTraceManager()); + } + addFirstEventHandler(displayId, mAutoclickController); + } + + if ((mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) { + TouchExplorer explorer = new TouchExplorer(displayContext, mAms); + if ((mEnabledFeatures & FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0) { + explorer.setServiceHandlesDoubleTap(true); + } + if ((mEnabledFeatures & FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0) { + explorer.setMultiFingerGesturesEnabled(true); + } + if ((mEnabledFeatures & FLAG_REQUEST_2_FINGER_PASSTHROUGH) != 0) { + explorer.setTwoFingerPassthroughEnabled(true); + } + if ((mEnabledFeatures & FLAG_SEND_MOTION_EVENTS) != 0) { + explorer.setSendMotionEventsEnabled(true); + } + addFirstEventHandler(displayId, explorer); + mTouchExplorer.put(displayId, explorer); + } + + if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0 + || ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) + || ((mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0)) { + final MagnificationGestureHandler magnificationGestureHandler = + createMagnificationGestureHandler(displayId, + displayContext); + addFirstEventHandler(displayId, magnificationGestureHandler); + mMagnificationGestureHandler.put(displayId, magnificationGestureHandler); + } + + if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) { + MotionEventInjector injector = new MotionEventInjector( + mContext.getMainLooper(), mAms.getTraceManager()); + addFirstEventHandler(displayId, injector); + mMotionEventInjectors.put(displayId, injector); + } + } + + private void enableDisplayIndependentFeatures() { if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) { mAms.setMotionEventInjectors(mMotionEventInjectors); } @@ -507,55 +536,57 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo mEventHandler.put(displayId, eventHandler); } - /** - * Adds an event handler to the event handler chain for all displays. The handler is added at - * the beginning of the chain. - * - * @param displayList The list of displays - * @param handler The handler to be added to the event handlers list. - */ - private void addFirstEventHandlerForAllDisplays(ArrayList displayList, - EventStreamTransformation handler) { - for (int i = 0; i < displayList.size(); i++) { - final int displayId = displayList.get(i).getDisplayId(); - addFirstEventHandler(displayId, handler); + private void disableFeatures() { + final ArrayList displaysList = mAms.getValidDisplayList(); + + for (int i = displaysList.size() - 1; i >= 0; i--) { + disableFeaturesForDisplay(displaysList.get(i).getDisplayId()); + } + mAms.setMotionEventInjectors(null); + disableDisplayIndependentFeatures(); + + resetAllStreamState(); + } + + private void disableFeaturesForDisplay(int displayId) { + if (DEBUG) { + Slog.i(TAG, "disableFeaturesForDisplay() : display Id = " + displayId); + } + + final MotionEventInjector injector = mMotionEventInjectors.get(displayId); + if (injector != null) { + injector.onDestroy(); + mMotionEventInjectors.remove(displayId); + } + + final TouchExplorer explorer = mTouchExplorer.get(displayId); + if (explorer != null) { + explorer.onDestroy(); + mTouchExplorer.remove(displayId); + } + + final MagnificationGestureHandler handler = mMagnificationGestureHandler.get(displayId); + if (handler != null) { + handler.onDestroy(); + mMagnificationGestureHandler.remove(displayId); + } + + final EventStreamTransformation eventStreamTransformation = mEventHandler.get(displayId); + if (eventStreamTransformation != null) { + mEventHandler.remove(displayId); } } - private void disableFeatures() { - for (int i = mMotionEventInjectors.size() - 1; i >= 0; i--) { - final MotionEventInjector injector = mMotionEventInjectors.valueAt(i); - if (injector != null) { - injector.onDestroy(); - } - } - mAms.setMotionEventInjectors(null); - mMotionEventInjectors.clear(); + private void disableDisplayIndependentFeatures() { if (mAutoclickController != null) { mAutoclickController.onDestroy(); mAutoclickController = null; } - for (int i = mTouchExplorer.size() - 1; i >= 0; i--) { - final TouchExplorer explorer = mTouchExplorer.valueAt(i); - if (explorer != null) { - explorer.onDestroy(); - } - } - mTouchExplorer.clear(); - for (int i = mMagnificationGestureHandler.size() - 1; i >= 0; i--) { - final MagnificationGestureHandler handler = mMagnificationGestureHandler.valueAt(i); - if (handler != null) { - handler.onDestroy(); - } - } - mMagnificationGestureHandler.clear(); + if (mKeyboardInterceptor != null) { mKeyboardInterceptor.onDestroy(); mKeyboardInterceptor = null; } - - mEventHandler.clear(); - resetStreamState(); } private MagnificationGestureHandler createMagnificationGestureHandler( @@ -584,18 +615,32 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo return magnificationGestureHandler; } - void resetStreamState() { - if (mTouchScreenStreamState != null) { - mTouchScreenStreamState.reset(); - } - if (mMouseStreamState != null) { - mMouseStreamState.reset(); + void resetAllStreamState() { + final ArrayList displaysList = mAms.getValidDisplayList(); + + for (int i = displaysList.size() - 1; i >= 0; i--) { + resetStreamStateForDisplay(displaysList.get(i).getDisplayId()); } + if (mKeyboardStreamState != null) { mKeyboardStreamState.reset(); } } + void resetStreamStateForDisplay(int displayId) { + final EventStreamState touchScreenStreamState = mTouchScreenStreamStates.get(displayId); + if (touchScreenStreamState != null) { + touchScreenStreamState.reset(); + mTouchScreenStreamStates.remove(displayId); + } + + final EventStreamState mouseStreamState = mMouseStreamStates.get(displayId); + if (mouseStreamState != null) { + mouseStreamState.reset(); + mMouseStreamStates.remove(displayId); + } + } + @Override public void onDestroy() { /* ignore */ @@ -846,4 +891,45 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo mTouchExplorer.get(displayId).setTouchExplorationPassthroughRegion(region); } } + + /** + * Dumps all {@link AccessibilityInputFilter}s here. + */ + public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { + if (mEventHandler == null) { + return; + } + pw.append("A11yInputFilter Info : "); + pw.println(); + + final ArrayList displaysList = mAms.getValidDisplayList(); + for (int i = 0; i < displaysList.size(); i++) { + final int displayId = displaysList.get(i).getDisplayId(); + EventStreamTransformation next = mEventHandler.get(displayId); + if (next != null) { + pw.append("Enabled features of Display ["); + pw.append(Integer.toString(displayId)); + pw.append("] = "); + + final StringJoiner joiner = new StringJoiner(",", "[", "]"); + + while (next != null) { + if (next instanceof MagnificationGestureHandler) { + joiner.add("MagnificationGesture"); + } else if (next instanceof KeyboardInterceptor) { + joiner.add("KeyboardInterceptor"); + } else if (next instanceof TouchExplorer) { + joiner.add("TouchExplorer"); + } else if (next instanceof AutoclickController) { + joiner.add("AutoclickController"); + } else if (next instanceof MotionEventInjector) { + joiner.add("MotionEventInjector"); + } + next = next.getNext(); + } + pw.append(joiner.toString()); + } + pw.println(); + } + } } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index ce8943f518ec9..7b2b8e4e50e0e 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -3340,6 +3340,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub pw.println(); } mA11yWindowManager.dump(fd, pw, args); + if (mHasInputFilter && mInputFilter != null) { + mInputFilter.dump(fd, pw, args); + } pw.println("Global client list info:{"); mGlobalClients.dump(pw, " Client list "); pw.println(" Registered clients:{"); @@ -3587,7 +3590,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub synchronized (mLock) { mDisplaysList.add(display); if (mInputFilter != null) { - mInputFilter.onDisplayChanged(); + mInputFilter.onDisplayAdded(display); } AccessibilityUserState userState = getCurrentUserStateLocked(); if (displayId != Display.DEFAULT_DISPLAY) { @@ -3609,7 +3612,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return; } if (mInputFilter != null) { - mInputFilter.onDisplayChanged(); + mInputFilter.onDisplayRemoved(displayId); } AccessibilityUserState userState = getCurrentUserStateLocked(); if (displayId != Display.DEFAULT_DISPLAY) { diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java index 80e81d6e7cb96..554f0a4265be0 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java @@ -29,6 +29,7 @@ import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEA import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -176,7 +177,7 @@ public class AccessibilityInputFilterTest { } @Test - public void testEventHandler_shouldChangeAfterOnDisplayChanged() { + public void testEventHandler_shouldIncreaseAndHaveCorrectOrderAfterOnDisplayAdded() { prepareLooper(); // Check if there is only one mEventHandler when there is one default display. @@ -184,13 +185,51 @@ public class AccessibilityInputFilterTest { assertEquals(1, mEventHandler.size()); // Check if it has correct numbers of mEventHandler for corresponding displays. - setDisplayCount(4); - mA11yInputFilter.onDisplayChanged(); - assertEquals(4, mEventHandler.size()); + setDisplayCount(2); + mA11yInputFilter.onDisplayAdded(mDisplayList.get(SECOND_DISPLAY)); + assertEquals(2, mEventHandler.size()); + + EventStreamTransformation next = mEventHandler.get(SECOND_DISPLAY); + assertNotNull(next); + + // Start from index 1 because KeyboardInterceptor only exists in EventHandler for + // DEFAULT_DISPLAY. + for (int i = 1; next != null; i++) { + assertEquals(next.getClass(), mExpectedEventHandlerTypes[i]); + next = next.getNext(); + } + } + + @Test + public void testEventHandler_shouldDecreaseAfterOnDisplayRemoved() { + prepareLooper(); setDisplayCount(2); - mA11yInputFilter.onDisplayChanged(); + mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures); assertEquals(2, mEventHandler.size()); + + // Check if it has correct numbers of mEventHandler for corresponding displays. + mA11yInputFilter.onDisplayRemoved(SECOND_DISPLAY); + assertEquals(1, mEventHandler.size()); + + EventStreamTransformation eventHandler = mEventHandler.get(SECOND_DISPLAY); + assertNull(eventHandler); + } + + @Test + public void testEventHandler_shouldNoChangedInOtherDisplayAfterOnDisplayRemoved() { + prepareLooper(); + + setDisplayCount(2); + mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures); + EventStreamTransformation eventHandlerBeforeDisplayRemoved = + mEventHandler.get(DEFAULT_DISPLAY); + + mA11yInputFilter.onDisplayRemoved(SECOND_DISPLAY); + EventStreamTransformation eventHandlerAfterDisplayRemoved = + mEventHandler.get(DEFAULT_DISPLAY); + + assertEquals(eventHandlerBeforeDisplayRemoved, eventHandlerAfterDisplayRemoved); } @Test @@ -240,7 +279,7 @@ public class AccessibilityInputFilterTest { } @Test - public void testInputEvent_shouldClearEventsForAllEventHandlers() { + public void testInputEvent_shouldClearEventsForDisplayEventHandlers() { prepareLooper(); mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures); @@ -253,12 +292,70 @@ public class AccessibilityInputFilterTest { send(downEvent(DEFAULT_DISPLAY, InputDevice.SOURCE_TOUCHSCREEN)); assertEquals(2, mCaptor1.mEvents.size()); - // InputEvent with different input source should trigger clearEvents() for each - // EventStreamTransformation in EventHandler. + // InputEvent with different input source to the same display should trigger + // clearEvents() for the EventHandler in this display. send(downEvent(DEFAULT_DISPLAY, InputDevice.SOURCE_MOUSE)); assertEquals(1, mCaptor1.mEvents.size()); } + @Test + public void testInputEvent_shouldNotClearEventsForOtherDisplayEventHandlers() { + prepareLooper(); + + setDisplayCount(2); + mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures); + assertEquals(2, mEventHandler.size()); + + mCaptor1 = new EventCaptor(); + mCaptor2 = new EventCaptor(); + mEventHandler.put(DEFAULT_DISPLAY, mCaptor1); + mEventHandler.put(SECOND_DISPLAY, mCaptor2); + + // InputEvent with different displayId should be dispatched to corresponding EventHandler. + send(downEvent(DEFAULT_DISPLAY, InputDevice.SOURCE_TOUCHSCREEN)); + send(downEvent(DEFAULT_DISPLAY, InputDevice.SOURCE_TOUCHSCREEN)); + send(downEvent(SECOND_DISPLAY, InputDevice.SOURCE_TOUCHSCREEN)); + + // InputEvent with different input source should not trigger clearEvents() for + // the EventHandler in the other display. + send(downEvent(SECOND_DISPLAY, InputDevice.SOURCE_MOUSE)); + assertEquals(2, mCaptor1.mEvents.size()); + } + + @Test + public void testInputEvent_shouldNotClearEventsForOtherDisplayAfterOnDisplayAdded() { + prepareLooper(); + + mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures); + mCaptor1 = new EventCaptor(); + mEventHandler.put(DEFAULT_DISPLAY, mCaptor1); + + send(downEvent(DEFAULT_DISPLAY, InputDevice.SOURCE_TOUCHSCREEN)); + send(downEvent(DEFAULT_DISPLAY, InputDevice.SOURCE_TOUCHSCREEN)); + assertEquals(2, mCaptor1.mEvents.size()); + + setDisplayCount(2); + mA11yInputFilter.onDisplayAdded(mDisplayList.get(SECOND_DISPLAY)); + assertEquals(2, mCaptor1.mEvents.size()); + } + + @Test + public void testInputEvent_shouldNotClearEventsForOtherDisplayAfterOnDisplayRemoved() { + prepareLooper(); + + setDisplayCount(2); + mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures); + mCaptor1 = new EventCaptor(); + mEventHandler.put(DEFAULT_DISPLAY, mCaptor1); + + send(downEvent(DEFAULT_DISPLAY, InputDevice.SOURCE_TOUCHSCREEN)); + send(downEvent(DEFAULT_DISPLAY, InputDevice.SOURCE_TOUCHSCREEN)); + assertEquals(2, mCaptor1.mEvents.size()); + + mA11yInputFilter.onDisplayRemoved(SECOND_DISPLAY); + assertEquals(2, mCaptor1.mEvents.size()); + } + @Test public void testEnabledFeatures_windowMagnificationMode_expectedMagnificationGestureHandler() { prepareLooper();