blob: 23ce483be10764192f8e0724093df8d3fb3616cb [file] [log] [blame]
/*
* 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 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.view.KeyEvent;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.accessibility.KeyEventDispatcher.KeyEventFilter;
import com.android.server.policy.WindowManagerPolicy;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import java.util.Arrays;
import java.util.Collections;
/**
* 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 mInputEventsHandler;
private KeyEventDispatcher mKeyEventDispatcher;
private KeyEventFilter mKeyEventFilter1;
private KeyEventFilter mKeyEventFilter2;
private IPowerManager mMockPowerManagerService;
private MessageCapturingHandler mMessageCapturingHandler;
private ArgumentCaptor<Integer> mFilter1SequenceCaptor = ArgumentCaptor.forClass(Integer.class);
private ArgumentCaptor<Integer> mFilter2SequenceCaptor = ArgumentCaptor.forClass(Integer.class);
@Before
public void setUp() {
Looper looper = InstrumentationRegistry.getContext().getMainLooper();
mInputEventsHandler = new MessageCapturingHandler(looper, null);
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(looper));
mMessageCapturingHandler = new MessageCapturingHandler(looper, null);
mKeyEventDispatcher = new KeyEventDispatcher(mInputEventsHandler, 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);
}
@After
public void tearDown() {
mInputEventsHandler.removeAllMessages();
mMessageCapturingHandler.removeAllMessages();
}
@Test
public void testNotifyKeyEvent_withNoBoundServices_shouldReturnFalse() {
assertFalse(mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Collections.EMPTY_LIST));
assertFalse(isTimeoutPending(mMessageCapturingHandler));
}
@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(isTimeoutPending(mMessageCapturingHandler));
}
@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(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
verifyZeroInteractions(mMockPowerManagerService);
assertFalse(isTimeoutPending(mMessageCapturingHandler));
}
@Test
public void testSetOnKeyResult_eventHandled_shouldNotPassEventToFramework()
throws RemoteException {
mKeyEventDispatcher
.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
mFilter1SequenceCaptor.getValue());
assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
assertFalse(isTimeoutPending(mMessageCapturingHandler));
}
@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(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
verifyZeroInteractions(mMockPowerManagerService);
assertFalse(isTimeoutPending(mMessageCapturingHandler));
}
@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(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
assertFalse(isTimeoutPending(mMessageCapturingHandler));
}
@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(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
assertFalse(isTimeoutPending(mMessageCapturingHandler));
}
@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(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
assertFalse(isTimeoutPending(mMessageCapturingHandler));
}
// 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(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
// Verify event is sent properly when other service responds
mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
mFilter2SequenceCaptor.getValue());
assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
verifyZeroInteractions(mMockPowerManagerService);
assertFalse(isTimeoutPending(mMessageCapturingHandler));
}
/*
* Timeouts
*/
@Test
public void testEventTimesOut_shouldPassToFramework() throws RemoteException {
mKeyEventDispatcher.notifyKeyEventLocked(
mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
assertEquals(1, mMessageCapturingHandler.timedMessages.size());
mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
assertTrue(mInputEventsHandler.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(getTimedMessage(mMessageCapturingHandler, 0));
assertTrue(mInputEventsHandler.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(getTimedMessage(mMessageCapturingHandler, 0));
assertFalse(mInputEventsHandler.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(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
assertEquals(1, mMessageCapturingHandler.timedMessages.size());
mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
mInputEventsHandler.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
mFilter1SequenceCaptor.getValue());
assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
verifyZeroInteractions(mMockPowerManagerService);
}
@Test
public void testEventTimesOut_afterServiceReturnsFalse_shouldPassToFrameworkOnce() {
mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
mFilter1SequenceCaptor.getValue());
assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
mInputEventsHandler.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
assertEquals(1, mMessageCapturingHandler.timedMessages.size());
mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
assertFalse(mInputEventsHandler.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(getTimedMessage(mMessageCapturingHandler, 0));
assertFalse(mInputEventsHandler.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(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
mKeyEventDispatcher.flush(mKeyEventFilter1);
assertTrue(mInputEventsHandler.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(mInputEventsHandler.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(mInputEventsHandler.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(mInputEventsHandler.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(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
mFilter1SequenceCaptor.getAllValues().get(0));
mInputEventsHandler.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(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
mFilter1SequenceCaptor.getAllValues().get(0));
mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
mFilter1SequenceCaptor.getAllValues().get(1));
assertFalse(mInputEventsHandler.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(mInputEventsHandler.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(mInputEventsHandler.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(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 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(mInputEventsHandler.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(mInputEventsHandler.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, mInputEventsHandler.timedMessages.size());
Message m = getTimedMessage(mInputEventsHandler, 0);
assertEquals(SEND_FRAMEWORK_KEY_EVENT, m.what);
assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, m.arg1);
assertTrue(new KeyEventMatcher(event).matches(m.obj));
}
private void assertTwoKeyEventsSentToFrameworkInOrder(KeyEvent first, KeyEvent second) {
assertEquals(2, mInputEventsHandler.timedMessages.size());
Message m0 = getTimedMessage(mInputEventsHandler, 0);
assertEquals(SEND_FRAMEWORK_KEY_EVENT, m0.what);
assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, m0.arg1);
assertTrue(new KeyEventMatcher(first).matches(m0.obj));
Message m1 = getTimedMessage(mInputEventsHandler, 1);
assertEquals(SEND_FRAMEWORK_KEY_EVENT, m1.what);
assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, m1.arg1);
assertTrue(new KeyEventMatcher(second).matches(m1.obj));
}
private static Message getTimedMessage(MessageCapturingHandler handler, int i) {
return handler.timedMessages.get(i).first;
}
private static boolean isTimeoutPending(MessageCapturingHandler handler) {
return handler.hasMessages(KeyEventDispatcher.MSG_ON_KEY_EVENT_TIMEOUT);
}
private class KeyEventMatcher extends TypeSafeMatcher<KeyEvent> {
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");
}
}
}