KeyEventDispatcherTest.java revision 8c1e36b440e8484123604975620b8675f0ad64a5
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.accessibility;
18
19import static junit.framework.TestCase.assertEquals;
20import static junit.framework.TestCase.assertFalse;
21import static junit.framework.TestCase.assertTrue;
22import static org.mockito.Matchers.anyInt;
23import static org.mockito.Matchers.anyLong;
24import static org.mockito.Matchers.anyObject;
25import static org.mockito.Matchers.argThat;
26import static org.mockito.Matchers.eq;
27import static org.mockito.Mockito.mock;
28import static org.mockito.Mockito.times;
29import static org.mockito.Mockito.verify;
30import static org.mockito.Mockito.verifyZeroInteractions;
31import static org.mockito.Mockito.when;
32
33import java.util.ArrayList;
34import java.util.Arrays;
35import java.util.Collections;
36import java.util.List;
37
38import android.content.Context;
39import android.os.Handler;
40import android.os.IPowerManager;
41import android.os.Looper;
42import android.os.Message;
43import android.os.PowerManager;
44import android.os.RemoteException;
45import android.support.test.runner.AndroidJUnit4;
46import android.view.KeyEvent;
47import android.view.WindowManagerPolicy;
48import com.android.server.accessibility.KeyEventDispatcher.KeyEventFilter;
49import org.junit.Before;
50import org.junit.Test;
51import org.junit.runner.RunWith;
52import org.mockito.ArgumentCaptor;
53import org.mockito.ArgumentMatcher;
54
55/**
56 * Tests for KeyEventDispatcher
57 */
58@RunWith(AndroidJUnit4.class)
59public class KeyEventDispatcherTest {
60    private static final int SEND_FRAMEWORK_KEY_EVENT = 4;
61
62    private final KeyEvent mKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, 0x40);
63    private final KeyEvent mOtherKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, 0x50);
64    private final Object mLock = new Object();
65    private MessageCapturingHandler mInputEventsHander;
66    private KeyEventDispatcher mKeyEventDispatcher;
67    private KeyEventFilter mKeyEventFilter1;
68    private KeyEventFilter mKeyEventFilter2;
69    private IPowerManager mMockPowerManagerService;
70    private MessageCapturingHandler mMessageCapturingHandler;
71    private ArgumentCaptor<Integer> mFilter1SequenceCaptor = ArgumentCaptor.forClass(Integer.class);
72    private ArgumentCaptor<Integer> mFilter2SequenceCaptor = ArgumentCaptor.forClass(Integer.class);
73
74    static {
75        Looper.prepare();
76    }
77
78    @Before
79    public void setUp() {
80        mInputEventsHander = new MessageCapturingHandler();
81        mMockPowerManagerService = mock(IPowerManager.class);
82        // TODO: It would be better to mock PowerManager rather than its binder, but the class is
83        // final.
84        PowerManager powerManager =
85                new PowerManager(mock(Context.class), mMockPowerManagerService, new Handler());
86        mMessageCapturingHandler = new MessageCapturingHandler();
87        mKeyEventDispatcher = new KeyEventDispatcher(mInputEventsHander, SEND_FRAMEWORK_KEY_EVENT,
88                mLock, powerManager, mMessageCapturingHandler);
89
90        mKeyEventFilter1 = mock(KeyEventFilter.class);
91        when(mKeyEventFilter1.onKeyEvent((KeyEvent) anyObject(),
92                mFilter1SequenceCaptor.capture().intValue()))
93                .thenReturn(true);
94
95        mKeyEventFilter2 = mock(KeyEventFilter.class);
96        when(mKeyEventFilter2.onKeyEvent((KeyEvent) anyObject(),
97                mFilter2SequenceCaptor.capture().intValue()))
98                .thenReturn(true);
99    }
100
101    @Test
102    public void testNotifyKeyEvent_withNoBoundServices_shouldReturnFalse() {
103        assertFalse(mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Collections.EMPTY_LIST));
104        assertFalse(mMessageCapturingHandler.isTimeoutPending());
105    }
106
107    @Test
108    public void testNotifyKeyEvent_boundServiceDoesntProcessEvents_shouldReturnFalse() {
109        KeyEventFilter keyEventFilter = mock(KeyEventFilter.class);
110        when(keyEventFilter.onKeyEvent((KeyEvent) anyObject(), anyInt())).thenReturn(false);
111        assertFalse(mKeyEventDispatcher
112                .notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(keyEventFilter)));
113        assertFalse(mMessageCapturingHandler.isTimeoutPending());
114    }
115
116    @Test
117    public void testNotifyKeyEvent_withOneValidService_shouldNotifyService()
118            throws RemoteException {
119        assertTrue(mKeyEventDispatcher
120                .notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1)));
121        verify(mKeyEventFilter1, times(1)).onKeyEvent(argThat(new KeyEventMatcher(mKeyEvent)),
122                anyInt());
123    }
124
125    @Test
126    public void testNotifyKeyEvent_withTwoValidService_shouldNotifyBoth() throws RemoteException {
127        assertTrue(mKeyEventDispatcher.notifyKeyEventLocked(
128                mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2)));
129        verify(mKeyEventFilter1, times(1)).onKeyEvent(argThat(new KeyEventMatcher(mKeyEvent)),
130                anyInt());
131        verify(mKeyEventFilter2, times(1)).onKeyEvent(argThat(new KeyEventMatcher(mKeyEvent)),
132                anyInt());
133    }
134
135    /*
136     * Results from services
137     */
138    @Test
139    public void testSetOnKeyResult_eventNotHandled_shouldPassEventToFramework() {
140        mKeyEventDispatcher
141                .notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
142
143        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
144                mFilter1SequenceCaptor.getValue());
145
146        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
147        verifyZeroInteractions(mMockPowerManagerService);
148        assertFalse(mMessageCapturingHandler.isTimeoutPending());
149    }
150
151    @Test
152    public void testSetOnKeyResult_eventHandled_shouldNotPassEventToFramework()
153            throws RemoteException {
154        mKeyEventDispatcher
155                .notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
156
157        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
158                mFilter1SequenceCaptor.getValue());
159
160        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
161        verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
162                eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
163        assertFalse(mMessageCapturingHandler.isTimeoutPending());
164    }
165
166    @Test
167    public void testSetOnKeyResult_twoServicesReturnsFalse_shouldPassEventToFramework() {
168        mKeyEventDispatcher.notifyKeyEventLocked(
169                mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
170
171        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
172                mFilter1SequenceCaptor.getValue());
173        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
174                mFilter2SequenceCaptor.getValue());
175
176        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
177        verifyZeroInteractions(mMockPowerManagerService);
178        assertFalse(mMessageCapturingHandler.isTimeoutPending());
179    }
180
181    @Test
182    public void testSetOnKeyResult_twoServicesReturnsTrue_shouldNotPassEventToFramework()
183            throws RemoteException {
184        mKeyEventDispatcher.notifyKeyEventLocked(
185                mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
186
187        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
188                mFilter1SequenceCaptor.getValue());
189        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true,
190                mFilter2SequenceCaptor.getValue());
191
192        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
193        verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
194                eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
195        assertFalse(mMessageCapturingHandler.isTimeoutPending());
196    }
197
198    @Test
199    public void testSetOnKeyResult_firstOfTwoServicesReturnsTrue_shouldNotPassEventToFramework()
200            throws RemoteException {
201        mKeyEventDispatcher.notifyKeyEventLocked(
202                mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
203
204        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
205                mFilter1SequenceCaptor.getValue());
206        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
207                mFilter2SequenceCaptor.getValue());
208
209        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
210        verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
211                eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
212        assertFalse(mMessageCapturingHandler.isTimeoutPending());
213    }
214
215    @Test
216    public void testSetOnKeyResult_secondOfTwoServicesReturnsTrue_shouldNotPassEventToFramework()
217            throws RemoteException {
218        mKeyEventDispatcher.notifyKeyEventLocked(
219                mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
220
221        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
222                mFilter1SequenceCaptor.getValue());
223        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true,
224                mFilter2SequenceCaptor.getValue());
225
226        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
227        verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
228                eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
229        assertFalse(mMessageCapturingHandler.isTimeoutPending());
230    }
231
232    // Each event should have its result set only once, but if it's set twice, we should ignore
233    // the second time.
234    @Test
235    public void testSetOnKeyResult_firstServiceReturnsTwice_secondShouldBeIgnored() {
236        mKeyEventDispatcher.notifyKeyEventLocked(
237                mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
238
239        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
240                mFilter1SequenceCaptor.getValue());
241        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
242                mFilter1SequenceCaptor.getValue());
243        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
244
245        // Verify event is sent properly when other service responds
246        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
247                mFilter2SequenceCaptor.getValue());
248        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
249        verifyZeroInteractions(mMockPowerManagerService);
250        assertFalse(mMessageCapturingHandler.isTimeoutPending());
251    }
252
253
254    /*
255     * Timeouts
256     */
257    @Test
258    public void testEventTimesOut_shouldPassToFramework() throws RemoteException {
259        mKeyEventDispatcher.notifyKeyEventLocked(
260                mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
261
262        assertEquals(1, mMessageCapturingHandler.timedMessages.size());
263        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
264
265        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
266        verifyZeroInteractions(mMockPowerManagerService);
267    }
268
269    @Test
270    public void testEventTimesOut_afterOneServiceReturnsFalse_shouldPassToFramework() {
271        mKeyEventDispatcher.notifyKeyEventLocked(
272                mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
273
274        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
275                mFilter1SequenceCaptor.getValue());
276
277        assertEquals(1, mMessageCapturingHandler.timedMessages.size());
278        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
279
280        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
281        verifyZeroInteractions(mMockPowerManagerService);
282    }
283
284    @Test
285    public void testEventTimesOut_afterOneServiceReturnsTrue_shouldNotPassToFramework()
286            throws RemoteException {
287        mKeyEventDispatcher.notifyKeyEventLocked(
288                mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
289
290        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
291                mFilter1SequenceCaptor.getValue());
292
293        assertEquals(1, mMessageCapturingHandler.timedMessages.size());
294        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
295
296        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
297        verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
298                eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
299    }
300
301    @Test
302    public void testEventTimesOut_thenServiceReturnsFalse_shouldPassToFrameworkOnce() {
303        mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
304        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
305
306        assertEquals(1, mMessageCapturingHandler.timedMessages.size());
307        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
308        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
309
310        mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
311        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
312                mFilter1SequenceCaptor.getValue());
313
314        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
315        verifyZeroInteractions(mMockPowerManagerService);
316    }
317
318    @Test
319    public void testEventTimesOut_afterServiceReturnsFalse_shouldPassToFrameworkOnce() {
320        mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
321        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
322
323        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
324                mFilter1SequenceCaptor.getValue());
325        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
326
327        mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
328        assertEquals(1, mMessageCapturingHandler.timedMessages.size());
329        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
330
331        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
332        verifyZeroInteractions(mMockPowerManagerService);
333    }
334
335    @Test
336    public void testEventTimesOut_afterServiceReturnsTrue_shouldNotPassToFramework()
337            throws RemoteException {
338        mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
339
340        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
341                mFilter1SequenceCaptor.getValue());
342        assertEquals(1, mMessageCapturingHandler.timedMessages.size());
343        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
344
345        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
346        verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
347                eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
348    }
349
350    /*
351     * Flush services
352     */
353    @Test
354    public void testFlushService_withPendingEvent_shouldPassToFramework() {
355        mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
356        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
357
358        mKeyEventDispatcher.flush(mKeyEventFilter1);
359
360        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
361    }
362
363    @Test
364    public void testFlushTwpServices_withPendingEvent_shouldPassToFramework() {
365        mKeyEventDispatcher.notifyKeyEventLocked(
366                mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
367
368        mKeyEventDispatcher.flush(mKeyEventFilter1);
369        mKeyEventDispatcher.flush(mKeyEventFilter2);
370
371        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
372    }
373
374    @Test
375    public void testFlushOneService_thenOtherReturnsTrue_shouldNotPassToFramework() {
376        mKeyEventDispatcher.notifyKeyEventLocked(
377                mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
378
379        mKeyEventDispatcher.flush(mKeyEventFilter1);
380        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true,
381                mFilter2SequenceCaptor.getValue());
382
383        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
384    }
385
386    @Test
387    public void testFlushOneService_thenOtherReturnsFalse_shouldPassToFramework() {
388        mKeyEventDispatcher.notifyKeyEventLocked(
389                mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
390
391        mKeyEventDispatcher.flush(mKeyEventFilter1);
392        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
393                mFilter2SequenceCaptor.getValue());
394
395        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
396    }
397
398    @Test
399    public void testFlushServiceWithNoEvents_shouldNotCrash() {
400        mKeyEventDispatcher.flush(mKeyEventFilter1);
401    }
402
403    /*
404     * Multiple Events
405     */
406    @Test
407    public void twoEvents_serviceReturnsFalse_sentToFramework() {
408        mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
409        mKeyEventDispatcher
410                .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
411        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
412
413        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
414                mFilter1SequenceCaptor.getAllValues().get(0));
415        mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
416        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
417                mFilter1SequenceCaptor.getAllValues().get(1));
418
419        assertTwoKeyEventsSentToFrameworkInOrder(mKeyEvent, mOtherKeyEvent);
420    }
421
422    @Test
423    public void twoEvents_serviceReturnsTrue_notSentToFramework() {
424        mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
425        mKeyEventDispatcher
426                .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
427        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
428
429        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
430                mFilter1SequenceCaptor.getAllValues().get(0));
431        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
432                mFilter1SequenceCaptor.getAllValues().get(1));
433
434        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
435    }
436
437    @Test
438    public void twoEvents_serviceHandlesFirst_otherSentToFramework() {
439        mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
440        mKeyEventDispatcher
441                .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
442        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
443
444        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
445                mFilter1SequenceCaptor.getAllValues().get(0));
446        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
447                mFilter1SequenceCaptor.getAllValues().get(1));
448
449        assertOneKeyEventSentToFramework(mOtherKeyEvent);
450    }
451
452    @Test
453    public void twoEvents_serviceHandlesSecond_otherSentToFramework() {
454        mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
455        mKeyEventDispatcher
456                .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
457        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
458
459        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
460                mFilter1SequenceCaptor.getAllValues().get(0));
461        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
462                mFilter1SequenceCaptor.getAllValues().get(1));
463
464        assertOneKeyEventSentToFramework(mKeyEvent);
465    }
466
467    @Test
468    public void twoEvents_firstTimesOutThenServiceHandlesBoth_firstSentToFramework() {
469        mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
470        mKeyEventDispatcher
471                .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
472        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
473
474        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
475        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
476                mFilter1SequenceCaptor.getAllValues().get(0));
477        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
478                mFilter1SequenceCaptor.getAllValues().get(1));
479
480        assertOneKeyEventSentToFramework(mKeyEvent);
481    }
482
483    @Test
484    public void addServiceBetweenTwoEvents_neitherEventHandled_bothSentToFramework() {
485        mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
486        mKeyEventDispatcher.notifyKeyEventLocked(
487                mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
488        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
489
490        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
491                mFilter2SequenceCaptor.getValue());
492        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
493                mFilter1SequenceCaptor.getAllValues().get(0));
494        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
495                mFilter1SequenceCaptor.getAllValues().get(1));
496
497        assertTwoKeyEventsSentToFrameworkInOrder(mKeyEvent, mOtherKeyEvent);
498    }
499
500    @Test
501    public void removeServiceBetweenTwoEvents_neitherEventHandled_bothSentToFramework() {
502        mKeyEventDispatcher.notifyKeyEventLocked(
503                mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
504        mKeyEventDispatcher.flush(mKeyEventFilter1);
505        mKeyEventDispatcher.notifyKeyEventLocked(
506                mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter2));
507        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
508
509        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
510                mFilter2SequenceCaptor.getAllValues().get(0));
511        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
512                mFilter2SequenceCaptor.getAllValues().get(1));
513
514        assertTwoKeyEventsSentToFrameworkInOrder(mKeyEvent, mOtherKeyEvent);
515    }
516
517    /*
518     * Misc
519     */
520    @Test
521    public void twoEvents_serviceReturnsFalseOutOfOrder_sentToFramework() {
522        mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
523        mKeyEventDispatcher
524                .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
525
526        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
527                mFilter1SequenceCaptor.getAllValues().get(1));
528        mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
529                mFilter1SequenceCaptor.getAllValues().get(0));
530
531        // Order doesn't really matter since this is really checking that we don't do something
532        // really bad, but we'll send them in the order they are reported
533        assertTwoKeyEventsSentToFrameworkInOrder(mOtherKeyEvent, mKeyEvent);
534    }
535
536    private void assertOneKeyEventSentToFramework(KeyEvent event) {
537        assertEquals(1, mInputEventsHander.timedMessages.size());
538        assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(0).what);
539        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER,
540                mInputEventsHander.timedMessages.get(0).arg1);
541        assertTrue(new KeyEventMatcher(event).matches(mInputEventsHander.timedMessages.get(0).obj));
542    }
543
544    private void assertTwoKeyEventsSentToFrameworkInOrder(KeyEvent first, KeyEvent second) {
545        assertEquals(2, mInputEventsHander.timedMessages.size());
546        assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(0).what);
547        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER,
548                mInputEventsHander.timedMessages.get(0).arg1);
549        assertTrue(new KeyEventMatcher(first).matches(mInputEventsHander.timedMessages.get(0).obj));
550        assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(1).what);
551        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER,
552                mInputEventsHander.timedMessages.get(1).arg1);
553        assertTrue(new KeyEventMatcher(second)
554                .matches(mInputEventsHander.timedMessages.get(1).obj));
555    }
556
557    private class KeyEventMatcher extends ArgumentMatcher<KeyEvent> {
558        private KeyEvent mEventToMatch;
559
560        KeyEventMatcher(KeyEvent eventToMatch) {
561            mEventToMatch = eventToMatch;
562        }
563
564        @Override
565        public boolean matches(Object event) {
566            if (!(event instanceof KeyEvent)) {
567                return false;
568            }
569            KeyEvent keyEvent = (KeyEvent) event;
570            return (mEventToMatch.getAction() == keyEvent.getAction())
571                    && (mEventToMatch.getKeyCode() == keyEvent.getKeyCode());
572        }
573    }
574
575    private class MessageCapturingHandler extends Handler {
576        List<Message> timedMessages = new ArrayList<>();
577
578        @Override
579        public boolean sendMessageAtTime(Message message, long uptimeMillis) {
580            timedMessages.add(Message.obtain(message));
581            return super.sendMessageAtTime(message, uptimeMillis);
582        }
583
584        public boolean isTimeoutPending() {
585            return hasMessages(KeyEventDispatcher.MSG_ON_KEY_EVENT_TIMEOUT);
586        }
587    }
588}
589