/* * Copyright (C) 2016 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 junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertTrue; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import static org.mockito.hamcrest.MockitoHamcrest.argThat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import android.content.Context; import android.os.Handler; import android.os.IPowerManager; import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; import android.support.test.runner.AndroidJUnit4; import android.view.KeyEvent; import android.view.WindowManagerPolicy; import com.android.server.accessibility.KeyEventDispatcher.KeyEventFilter; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; /** * Tests for KeyEventDispatcher */ @RunWith(AndroidJUnit4.class) public class KeyEventDispatcherTest { private static final int SEND_FRAMEWORK_KEY_EVENT = 4; private final KeyEvent mKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, 0x40); private final KeyEvent mOtherKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, 0x50); private final Object mLock = new Object(); private MessageCapturingHandler mInputEventsHander; private KeyEventDispatcher mKeyEventDispatcher; private KeyEventFilter mKeyEventFilter1; private KeyEventFilter mKeyEventFilter2; private IPowerManager mMockPowerManagerService; private MessageCapturingHandler mMessageCapturingHandler; private ArgumentCaptor mFilter1SequenceCaptor = ArgumentCaptor.forClass(Integer.class); private ArgumentCaptor mFilter2SequenceCaptor = ArgumentCaptor.forClass(Integer.class); @BeforeClass public static void oneTimeInitialization() { if (Looper.myLooper() == null) { Looper.prepare(); } } @Before public void setUp() { mInputEventsHander = new MessageCapturingHandler(); mMockPowerManagerService = mock(IPowerManager.class); // TODO: It would be better to mock PowerManager rather than its binder, but the class is // final. PowerManager powerManager = new PowerManager(mock(Context.class), mMockPowerManagerService, new Handler()); mMessageCapturingHandler = new MessageCapturingHandler(); mKeyEventDispatcher = new KeyEventDispatcher(mInputEventsHander, SEND_FRAMEWORK_KEY_EVENT, mLock, powerManager, mMessageCapturingHandler); mKeyEventFilter1 = mock(KeyEventFilter.class); when(mKeyEventFilter1.onKeyEvent((KeyEvent) anyObject(), mFilter1SequenceCaptor.capture().intValue())) .thenReturn(true); mKeyEventFilter2 = mock(KeyEventFilter.class); when(mKeyEventFilter2.onKeyEvent((KeyEvent) anyObject(), mFilter2SequenceCaptor.capture().intValue())) .thenReturn(true); } @Test public void testNotifyKeyEvent_withNoBoundServices_shouldReturnFalse() { assertFalse(mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Collections.EMPTY_LIST)); assertFalse(mMessageCapturingHandler.isTimeoutPending()); } @Test public void testNotifyKeyEvent_boundServiceDoesntProcessEvents_shouldReturnFalse() { KeyEventFilter keyEventFilter = mock(KeyEventFilter.class); when(keyEventFilter.onKeyEvent((KeyEvent) anyObject(), anyInt())).thenReturn(false); assertFalse(mKeyEventDispatcher .notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(keyEventFilter))); assertFalse(mMessageCapturingHandler.isTimeoutPending()); } @Test public void testNotifyKeyEvent_withOneValidService_shouldNotifyService() throws RemoteException { assertTrue(mKeyEventDispatcher .notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1))); verify(mKeyEventFilter1, times(1)).onKeyEvent(argThat(new KeyEventMatcher(mKeyEvent)), anyInt()); } @Test public void testNotifyKeyEvent_withTwoValidService_shouldNotifyBoth() throws RemoteException { assertTrue(mKeyEventDispatcher.notifyKeyEventLocked( mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2))); verify(mKeyEventFilter1, times(1)).onKeyEvent(argThat(new KeyEventMatcher(mKeyEvent)), anyInt()); verify(mKeyEventFilter2, times(1)).onKeyEvent(argThat(new KeyEventMatcher(mKeyEvent)), anyInt()); } /* * Results from services */ @Test public void testSetOnKeyResult_eventNotHandled_shouldPassEventToFramework() { mKeyEventDispatcher .notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getValue()); assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); assertFalse(mMessageCapturingHandler.isTimeoutPending()); } @Test public void testSetOnKeyResult_eventHandled_shouldNotPassEventToFramework() throws RemoteException { mKeyEventDispatcher .notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getValue()); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verify(mMockPowerManagerService, times(1)).userActivity(anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0)); assertFalse(mMessageCapturingHandler.isTimeoutPending()); } @Test public void testSetOnKeyResult_twoServicesReturnsFalse_shouldPassEventToFramework() { mKeyEventDispatcher.notifyKeyEventLocked( mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getValue()); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false, mFilter2SequenceCaptor.getValue()); assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); assertFalse(mMessageCapturingHandler.isTimeoutPending()); } @Test public void testSetOnKeyResult_twoServicesReturnsTrue_shouldNotPassEventToFramework() throws RemoteException { mKeyEventDispatcher.notifyKeyEventLocked( mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getValue()); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true, mFilter2SequenceCaptor.getValue()); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verify(mMockPowerManagerService, times(1)).userActivity(anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0)); assertFalse(mMessageCapturingHandler.isTimeoutPending()); } @Test public void testSetOnKeyResult_firstOfTwoServicesReturnsTrue_shouldNotPassEventToFramework() throws RemoteException { mKeyEventDispatcher.notifyKeyEventLocked( mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getValue()); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false, mFilter2SequenceCaptor.getValue()); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verify(mMockPowerManagerService, times(1)).userActivity(anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0)); assertFalse(mMessageCapturingHandler.isTimeoutPending()); } @Test public void testSetOnKeyResult_secondOfTwoServicesReturnsTrue_shouldNotPassEventToFramework() throws RemoteException { mKeyEventDispatcher.notifyKeyEventLocked( mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getValue()); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true, mFilter2SequenceCaptor.getValue()); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verify(mMockPowerManagerService, times(1)).userActivity(anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0)); assertFalse(mMessageCapturingHandler.isTimeoutPending()); } // Each event should have its result set only once, but if it's set twice, we should ignore // the second time. @Test public void testSetOnKeyResult_firstServiceReturnsTwice_secondShouldBeIgnored() { mKeyEventDispatcher.notifyKeyEventLocked( mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getValue()); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getValue()); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); // Verify event is sent properly when other service responds mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false, mFilter2SequenceCaptor.getValue()); assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); assertFalse(mMessageCapturingHandler.isTimeoutPending()); } /* * Timeouts */ @Test public void testEventTimesOut_shouldPassToFramework() throws RemoteException { mKeyEventDispatcher.notifyKeyEventLocked( mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); assertEquals(1, mMessageCapturingHandler.timedMessages.size()); mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); } @Test public void testEventTimesOut_afterOneServiceReturnsFalse_shouldPassToFramework() { mKeyEventDispatcher.notifyKeyEventLocked( mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getValue()); assertEquals(1, mMessageCapturingHandler.timedMessages.size()); mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); } @Test public void testEventTimesOut_afterOneServiceReturnsTrue_shouldNotPassToFramework() throws RemoteException { mKeyEventDispatcher.notifyKeyEventLocked( mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getValue()); assertEquals(1, mMessageCapturingHandler.timedMessages.size()); mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verify(mMockPowerManagerService, times(1)).userActivity(anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0)); } @Test public void testEventTimesOut_thenServiceReturnsFalse_shouldPassToFrameworkOnce() { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); assertEquals(1, mMessageCapturingHandler.timedMessages.size()); mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getValue()); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); } @Test public void testEventTimesOut_afterServiceReturnsFalse_shouldPassToFrameworkOnce() { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getValue()); assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT); assertEquals(1, mMessageCapturingHandler.timedMessages.size()); mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verifyZeroInteractions(mMockPowerManagerService); } @Test public void testEventTimesOut_afterServiceReturnsTrue_shouldNotPassToFramework() throws RemoteException { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getValue()); assertEquals(1, mMessageCapturingHandler.timedMessages.size()); mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); verify(mMockPowerManagerService, times(1)).userActivity(anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0)); } /* * Flush services */ @Test public void testFlushService_withPendingEvent_shouldPassToFramework() { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.flush(mKeyEventFilter1); assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); } @Test public void testFlushTwpServices_withPendingEvent_shouldPassToFramework() { mKeyEventDispatcher.notifyKeyEventLocked( mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); mKeyEventDispatcher.flush(mKeyEventFilter1); mKeyEventDispatcher.flush(mKeyEventFilter2); assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); } @Test public void testFlushOneService_thenOtherReturnsTrue_shouldNotPassToFramework() { mKeyEventDispatcher.notifyKeyEventLocked( mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); mKeyEventDispatcher.flush(mKeyEventFilter1); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true, mFilter2SequenceCaptor.getValue()); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); } @Test public void testFlushOneService_thenOtherReturnsFalse_shouldPassToFramework() { mKeyEventDispatcher.notifyKeyEventLocked( mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); mKeyEventDispatcher.flush(mKeyEventFilter1); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false, mFilter2SequenceCaptor.getValue()); assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); } @Test public void testFlushServiceWithNoEvents_shouldNotCrash() { mKeyEventDispatcher.flush(mKeyEventFilter1); } /* * Multiple Events */ @Test public void twoEvents_serviceReturnsFalse_sentToFramework() { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getAllValues().get(0)); mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getAllValues().get(1)); assertTwoKeyEventsSentToFrameworkInOrder(mKeyEvent, mOtherKeyEvent); } @Test public void twoEvents_serviceReturnsTrue_notSentToFramework() { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getAllValues().get(0)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getAllValues().get(1)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); } @Test public void twoEvents_serviceHandlesFirst_otherSentToFramework() { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getAllValues().get(0)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getAllValues().get(1)); assertOneKeyEventSentToFramework(mOtherKeyEvent); } @Test public void twoEvents_serviceHandlesSecond_otherSentToFramework() { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getAllValues().get(0)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getAllValues().get(1)); assertOneKeyEventSentToFramework(mKeyEvent); } @Test public void twoEvents_firstTimesOutThenServiceHandlesBoth_firstSentToFramework() { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getAllValues().get(0)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true, mFilter1SequenceCaptor.getAllValues().get(1)); assertOneKeyEventSentToFramework(mKeyEvent); } @Test public void addServiceBetweenTwoEvents_neitherEventHandled_bothSentToFramework() { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher.notifyKeyEventLocked( mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false, mFilter2SequenceCaptor.getValue()); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getAllValues().get(0)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getAllValues().get(1)); assertTwoKeyEventsSentToFrameworkInOrder(mKeyEvent, mOtherKeyEvent); } @Test public void removeServiceBetweenTwoEvents_neitherEventHandled_bothSentToFramework() { mKeyEventDispatcher.notifyKeyEventLocked( mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)); mKeyEventDispatcher.flush(mKeyEventFilter1); mKeyEventDispatcher.notifyKeyEventLocked( mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter2)); assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false, mFilter2SequenceCaptor.getAllValues().get(0)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false, mFilter2SequenceCaptor.getAllValues().get(1)); assertTwoKeyEventsSentToFrameworkInOrder(mKeyEvent, mOtherKeyEvent); } /* * Misc */ @Test public void twoEvents_serviceReturnsFalseOutOfOrder_sentToFramework() { mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getAllValues().get(1)); mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false, mFilter1SequenceCaptor.getAllValues().get(0)); // Order doesn't really matter since this is really checking that we don't do something // really bad, but we'll send them in the order they are reported assertTwoKeyEventsSentToFrameworkInOrder(mOtherKeyEvent, mKeyEvent); } private void assertOneKeyEventSentToFramework(KeyEvent event) { assertEquals(1, mInputEventsHander.timedMessages.size()); assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(0).what); assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, mInputEventsHander.timedMessages.get(0).arg1); assertTrue(new KeyEventMatcher(event).matches(mInputEventsHander.timedMessages.get(0).obj)); } private void assertTwoKeyEventsSentToFrameworkInOrder(KeyEvent first, KeyEvent second) { assertEquals(2, mInputEventsHander.timedMessages.size()); assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(0).what); assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, mInputEventsHander.timedMessages.get(0).arg1); assertTrue(new KeyEventMatcher(first).matches(mInputEventsHander.timedMessages.get(0).obj)); assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(1).what); assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, mInputEventsHander.timedMessages.get(1).arg1); assertTrue(new KeyEventMatcher(second) .matches(mInputEventsHander.timedMessages.get(1).obj)); } private class KeyEventMatcher extends TypeSafeMatcher { private KeyEvent mEventToMatch; KeyEventMatcher(KeyEvent eventToMatch) { mEventToMatch = eventToMatch; } @Override public boolean matchesSafely(KeyEvent keyEvent) { return (mEventToMatch.getAction() == keyEvent.getAction()) && (mEventToMatch.getKeyCode() == keyEvent.getKeyCode()); } @Override public void describeTo(Description description) { description.appendText("Key event matcher"); } } private class MessageCapturingHandler extends Handler { List timedMessages = new ArrayList<>(); @Override public boolean sendMessageAtTime(Message message, long uptimeMillis) { timedMessages.add(Message.obtain(message)); return super.sendMessageAtTime(message, uptimeMillis); } public boolean isTimeoutPending() { return hasMessages(KeyEventDispatcher.MSG_ON_KEY_EVENT_TIMEOUT); } } }