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