blob: 236b45894fb346b330183184bec08c1d6d28f504 [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.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.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* 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<Integer> mFilter1SequenceCaptor = ArgumentCaptor.forClass(Integer.class);
private ArgumentCaptor<Integer> 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<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");
}
}
private class MessageCapturingHandler extends Handler {
List<Message> 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);
}
}
}