xref: /aosp_15_r20/frameworks/base/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2022 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 
17 package com.android.server.input
18 
19 
20 import android.Manifest
21 import android.content.Context
22 import android.content.ContextWrapper
23 import android.content.PermissionChecker
24 import android.content.pm.PackageManager
25 import android.content.pm.PackageManagerInternal
26 import android.hardware.display.DisplayManager
27 import android.hardware.display.DisplayViewport
28 import android.hardware.display.VirtualDisplay
29 import android.hardware.input.InputManager
30 import android.hardware.input.InputManagerGlobal
31 import android.os.InputEventInjectionSync
32 import android.os.SystemClock
33 import android.os.test.TestLooper
34 import android.platform.test.annotations.EnableFlags
35 import android.platform.test.annotations.Presubmit
36 import android.platform.test.flag.junit.SetFlagsRule
37 import android.provider.Settings
38 import android.view.View.OnKeyListener
39 import android.view.InputDevice
40 import android.view.KeyCharacterMap
41 import android.view.KeyEvent
42 import android.view.SurfaceHolder
43 import android.view.SurfaceView
44 import android.view.WindowManager
45 import android.test.mock.MockContentResolver
46 import androidx.test.platform.app.InstrumentationRegistry
47 import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
48 import com.android.dx.mockito.inline.extended.ExtendedMockito
49 import com.android.internal.policy.KeyInterceptionInfo
50 import com.android.internal.util.test.FakeSettingsProvider
51 import com.android.modules.utils.testing.ExtendedMockitoRule
52 import com.android.server.LocalServices
53 import com.android.server.wm.WindowManagerInternal
54 import com.google.common.truth.Truth.assertThat
55 import org.junit.After
56 import org.junit.Assert.assertEquals
57 import org.junit.Assert.assertNotEquals
58 import org.junit.Assert.assertTrue
59 import org.junit.Before
60 import org.junit.Rule
61 import org.junit.Test
62 import org.mockito.ArgumentMatchers.any
63 import org.mockito.ArgumentMatchers.anyBoolean
64 import org.mockito.ArgumentMatchers.anyFloat
65 import org.mockito.ArgumentMatchers.anyInt
66 import org.mockito.ArgumentMatchers.eq
67 import org.mockito.Mock
68 import org.mockito.Mockito.mock
69 import org.mockito.Mockito.never
70 import org.mockito.Mockito.spy
71 import org.mockito.Mockito.times
72 import org.mockito.Mockito.verify
73 import org.mockito.Mockito.verifyZeroInteractions
74 import org.mockito.Mockito.`when`
75 import org.mockito.stubbing.OngoingStubbing
76 
77 /**
78  * Tests for {@link InputManagerService}.
79  *
80  * Build/Install/Run:
81  * atest InputTests:InputManagerServiceTests
82  */
83 @Presubmit
84 class InputManagerServiceTests {
85 
86     companion object {
87         val ACTION_KEY_EVENTS = listOf(
88             KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_META_LEFT),
89             KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_META_RIGHT),
90             KeyEvent( /* downTime= */0, /* eventTime= */0, /* action= */0, /* code= */0,
91                 /* repeat= */0, KeyEvent.META_META_ON
92             )
93         )
94     }
95 
96     @get:Rule
97     val extendedMockitoRule =
98         ExtendedMockitoRule.Builder(this)
99             .mockStatic(LocalServices::class.java)
100             .mockStatic(PermissionChecker::class.java)
101             .mockStatic(KeyCharacterMap::class.java)
102             .build()!!
103 
104     @get:Rule
105     val setFlagsRule = SetFlagsRule()
106 
107     @get:Rule
108     val fakeSettingsProviderRule = FakeSettingsProvider.rule()!!
109 
110     @Mock
111     private lateinit var native: NativeInputManagerService
112 
113     @Mock
114     private lateinit var wmCallbacks: InputManagerService.WindowManagerCallbacks
115 
116     @Mock
117     private lateinit var windowManagerInternal: WindowManagerInternal
118 
119     @Mock
120     private lateinit var packageManagerInternal: PackageManagerInternal
121 
122     @Mock
123     private lateinit var uEventManager: UEventManager
124 
125     @Mock
126     private lateinit var kbdController: InputManagerService.KeyboardBacklightControllerInterface
127 
128     @Mock
129     private lateinit var kcm: KeyCharacterMap
130 
131     private lateinit var service: InputManagerService
132     private lateinit var localService: InputManagerInternal
133     private lateinit var context: Context
134     private lateinit var testLooper: TestLooper
135     private lateinit var contentResolver: MockContentResolver
136     private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
137 
138     @Before
setupnull139     fun setup() {
140         context = spy(ContextWrapper(InstrumentationRegistry.getInstrumentation().getContext()))
141         contentResolver = MockContentResolver(context)
142         contentResolver.addProvider(Settings.AUTHORITY, FakeSettingsProvider())
143         whenever(context.contentResolver).thenReturn(contentResolver)
144         testLooper = TestLooper()
145         service =
146             InputManagerService(object : InputManagerService.Injector(
147                     context, testLooper.looper, uEventManager) {
148                 override fun getNativeService(
149                     service: InputManagerService?
150                 ): NativeInputManagerService {
151                     return native
152                 }
153 
154                 override fun registerLocalService(service: InputManagerInternal?) {
155                     localService = service!!
156                 }
157 
158                 override fun getKeyboardBacklightController(
159                     nativeService: NativeInputManagerService?
160                 ): InputManagerService.KeyboardBacklightControllerInterface {
161                     return kbdController
162                 }
163             })
164         inputManagerGlobalSession = InputManagerGlobal.createTestSession(service)
165         val inputManager = InputManager(context)
166         whenever(context.getSystemService(InputManager::class.java)).thenReturn(inputManager)
167         whenever(context.getSystemService(Context.INPUT_SERVICE)).thenReturn(inputManager)
168         whenever(context.checkCallingOrSelfPermission(Manifest.permission.MANAGE_KEY_GESTURES))
169             .thenReturn(
170                 PackageManager.PERMISSION_GRANTED
171             )
172 
173         ExtendedMockito.doReturn(windowManagerInternal).`when` {
174             LocalServices.getService(eq(WindowManagerInternal::class.java))
175         }
176         ExtendedMockito.doReturn(packageManagerInternal).`when` {
177             LocalServices.getService(eq(PackageManagerInternal::class.java))
178         }
179         ExtendedMockito.doReturn(kcm).`when` {
180             KeyCharacterMap.load(anyInt())
181         }
182 
183         assertTrue("Local service must be registered", this::localService.isInitialized)
184         service.setWindowManagerCallbacks(wmCallbacks)
185     }
186 
187     @After
tearDownnull188     fun tearDown() {
189         if (this::inputManagerGlobalSession.isInitialized) {
190             inputManagerGlobalSession.close()
191         }
192     }
193 
194     @Test
testStartnull195     fun testStart() {
196         verifyZeroInteractions(native)
197 
198         service.start()
199         verify(native).start()
200     }
201 
202     @Test
testInputSettingsUpdatedOnSystemRunningnull203     fun testInputSettingsUpdatedOnSystemRunning() {
204         verifyZeroInteractions(native)
205 
206         runWithShellPermissionIdentity {
207             service.systemRunning()
208         }
209 
210         verify(native).setPointerSpeed(anyInt())
211         verify(native).setTouchpadPointerSpeed(anyInt())
212         verify(native).setTouchpadNaturalScrollingEnabled(anyBoolean())
213         verify(native).setTouchpadTapToClickEnabled(anyBoolean())
214         verify(native).setTouchpadTapDraggingEnabled(anyBoolean())
215         verify(native).setShouldNotifyTouchpadHardwareState(anyBoolean())
216         verify(native).setTouchpadRightClickZoneEnabled(anyBoolean())
217         verify(native).setTouchpadThreeFingerTapShortcutEnabled(anyBoolean())
218         verify(native).setTouchpadSystemGesturesEnabled(anyBoolean())
219         verify(native).setShowTouches(anyBoolean())
220         verify(native).setMotionClassifierEnabled(anyBoolean())
221         verify(native).setMaximumObscuringOpacityForTouch(anyFloat())
222         verify(native).setStylusPointerIconEnabled(anyBoolean())
223         // Called thrice at boot, since there are individual callbacks to update the
224         // key repeat timeout, the key repeat delay and whether key repeat enabled.
225         verify(native, times(3)).setKeyRepeatConfiguration(anyInt(), anyInt(),
226             anyBoolean())
227     }
228 
229     @Test
testPointerDisplayUpdatesWhenDisplayViewportsChangednull230     fun testPointerDisplayUpdatesWhenDisplayViewportsChanged() {
231         val displayId = 123
232         whenever(wmCallbacks.pointerDisplayId).thenReturn(displayId)
233         val viewports = listOf<DisplayViewport>()
234         localService.setDisplayViewports(viewports)
235         verify(native).setDisplayViewports(any(Array<DisplayViewport>::class.java))
236         verify(native).setPointerDisplayId(displayId)
237     }
238 
239     @Test
setDeviceTypeAssociation_setsDeviceTypeAssociationnull240     fun setDeviceTypeAssociation_setsDeviceTypeAssociation() {
241         val inputPort = "inputPort"
242         val type = "type"
243 
244         localService.setTypeAssociation(inputPort, type)
245 
246         assertThat(service.getDeviceTypeAssociations()).asList().containsExactly(inputPort, type)
247             .inOrder()
248     }
249 
250     @Test
setAndUnsetDeviceTypeAssociation_deviceTypeAssociationIsMissingnull251     fun setAndUnsetDeviceTypeAssociation_deviceTypeAssociationIsMissing() {
252         val inputPort = "inputPort"
253         val type = "type"
254 
255         localService.setTypeAssociation(inputPort, type)
256         localService.unsetTypeAssociation(inputPort)
257 
258         assertTrue(service.getDeviceTypeAssociations().isEmpty())
259     }
260 
261     @Test
testAddAndRemoveVirtualKeyboardLayoutAssociationnull262     fun testAddAndRemoveVirtualKeyboardLayoutAssociation() {
263         val inputPort = "input port"
264         val languageTag = "language"
265         val layoutType = "layoutType"
266         localService.addKeyboardLayoutAssociation(inputPort, languageTag, layoutType)
267         verify(native).changeKeyboardLayoutAssociation()
268 
269         localService.removeKeyboardLayoutAssociation(inputPort)
270         verify(native, times(2)).changeKeyboardLayoutAssociation()
271     }
272 
273     @Test
testActionKeyEventsForwardedToFocusedWindow_whenCorrectlyRequestednull274     fun testActionKeyEventsForwardedToFocusedWindow_whenCorrectlyRequested() {
275         service.systemRunning()
276         overrideSendActionKeyEventsToFocusedWindow(
277             /* hasPermission = */true,
278             /* hasPrivateFlag = */true
279         )
280         whenever(wmCallbacks.interceptKeyBeforeDispatching(any(), any(), anyInt())).thenReturn(-1)
281 
282         for (event in ACTION_KEY_EVENTS) {
283             assertEquals(0, service.interceptKeyBeforeDispatching(null, event, 0))
284         }
285     }
286 
287     @Test
testActionKeyEventsNotForwardedToFocusedWindow_whenNoPermissionsnull288     fun testActionKeyEventsNotForwardedToFocusedWindow_whenNoPermissions() {
289         service.systemRunning()
290         overrideSendActionKeyEventsToFocusedWindow(
291             /* hasPermission = */false,
292             /* hasPrivateFlag = */true
293         )
294         whenever(wmCallbacks.interceptKeyBeforeDispatching(any(), any(), anyInt())).thenReturn(-1)
295 
296         for (event in ACTION_KEY_EVENTS) {
297             assertNotEquals(0, service.interceptKeyBeforeDispatching(null, event, 0))
298         }
299     }
300 
301     @Test
testActionKeyEventsNotForwardedToFocusedWindow_whenNoPrivateFlagnull302     fun testActionKeyEventsNotForwardedToFocusedWindow_whenNoPrivateFlag() {
303         service.systemRunning()
304         overrideSendActionKeyEventsToFocusedWindow(
305             /* hasPermission = */true,
306             /* hasPrivateFlag = */false
307         )
308         whenever(wmCallbacks.interceptKeyBeforeDispatching(any(), any(), anyInt())).thenReturn(-1)
309 
310         for (event in ACTION_KEY_EVENTS) {
311             assertNotEquals(0, service.interceptKeyBeforeDispatching(null, event, 0))
312         }
313     }
314 
createVirtualDisplaysnull315     private fun createVirtualDisplays(count: Int): List<VirtualDisplay> {
316         val displayManager: DisplayManager = context.getSystemService(
317                 DisplayManager::class.java
318         ) as DisplayManager
319         val virtualDisplays = mutableListOf<VirtualDisplay>()
320         for (i in 0 until count) {
321             virtualDisplays.add(displayManager.createVirtualDisplay(
322                     /* displayName= */ "testVirtualDisplay$i",
323                     /* width= */ 100,
324                     /* height= */ 100,
325                     /* densityDpi= */ 100,
326                     /* surface= */ null,
327                     /* flags= */ 0
328             ))
329         }
330         return virtualDisplays
331     }
332 
333     // Helper function that creates a KeyEvent with Keycode A with the given action
createKeycodeAEventnull334     private fun createKeycodeAEvent(inputDevice: InputDevice, action: Int): KeyEvent {
335         val eventTime = SystemClock.uptimeMillis()
336         return KeyEvent(
337                 /* downTime= */ eventTime,
338                 /* eventTime= */ eventTime,
339                 /* action= */ action,
340                 /* code= */ KeyEvent.KEYCODE_A,
341                 /* repeat= */ 0,
342                 /* metaState= */ 0,
343                 /* deviceId= */ inputDevice.id,
344                 /* scanCode= */ 0,
345                 /* flags= */ KeyEvent.FLAG_FROM_SYSTEM,
346                 /* source= */ InputDevice.SOURCE_KEYBOARD
347         )
348     }
349 
createInputDevicenull350     private fun createInputDevice(): InputDevice {
351         return InputDevice.Builder()
352                 .setId(123)
353                 .setName("abc")
354                 .setDescriptor("def")
355                 .setSources(InputDevice.SOURCE_KEYBOARD)
356                 .build()
357     }
358 
359     @Test
addUniqueIdAssociationByDescriptor_verifyAssociationsnull360     fun addUniqueIdAssociationByDescriptor_verifyAssociations() {
361         // Overall goal is to have 2 displays and verify that events from the InputDevice are
362         // sent only to the view that is on the associated display.
363         // So, associate the InputDevice with display 1, then send and verify KeyEvents.
364         // Then remove associations, then associate the InputDevice with display 2, then send
365         // and verify commands.
366 
367         // Make 2 virtual displays with some mock SurfaceViews
368         val mockSurfaceView1 = mock(SurfaceView::class.java)
369         val mockSurfaceView2 = mock(SurfaceView::class.java)
370         val mockSurfaceHolder1 = mock(SurfaceHolder::class.java)
371         `when`(mockSurfaceView1.holder).thenReturn(mockSurfaceHolder1)
372         val mockSurfaceHolder2 = mock(SurfaceHolder::class.java)
373         `when`(mockSurfaceView2.holder).thenReturn(mockSurfaceHolder2)
374 
375         val virtualDisplays = createVirtualDisplays(2)
376 
377         // Simulate an InputDevice
378         val inputDevice = createInputDevice()
379 
380         // Associate input device with display
381         service.addUniqueIdAssociationByDescriptor(
382                 inputDevice.descriptor,
383                 virtualDisplays[0].display.displayId.toString()
384         )
385 
386         // Simulate 2 different KeyEvents
387         val downEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_DOWN)
388         val upEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_UP)
389 
390         // Create a mock OnKeyListener object
391         val mockOnKeyListener = mock(OnKeyListener::class.java)
392 
393         // Verify that the event went to Display 1 not Display 2
394         service.injectInputEvent(downEvent, InputEventInjectionSync.NONE)
395 
396         // Call the onKey method on the mock OnKeyListener object
397         mockOnKeyListener.onKey(mockSurfaceView1, /* keyCode= */ KeyEvent.KEYCODE_A, downEvent)
398         mockOnKeyListener.onKey(mockSurfaceView2, /* keyCode= */ KeyEvent.KEYCODE_A, upEvent)
399 
400         // Verify that the onKey method was called with the expected arguments
401         verify(mockOnKeyListener).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, downEvent)
402         verify(mockOnKeyListener, never()).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, downEvent)
403 
404         // Remove association
405         service.removeUniqueIdAssociationByDescriptor(inputDevice.descriptor)
406 
407         // Associate with Display 2
408         service.addUniqueIdAssociationByDescriptor(
409                 inputDevice.descriptor,
410                 virtualDisplays[1].display.displayId.toString()
411         )
412 
413         // Simulate a KeyEvent
414         service.injectInputEvent(upEvent, InputEventInjectionSync.NONE)
415 
416         // Verify that the event went to Display 2 not Display 1
417         verify(mockOnKeyListener).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, upEvent)
418         verify(mockOnKeyListener, never()).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, upEvent)
419     }
420 
421     @Test
addUniqueIdAssociationByPort_verifyAssociationsnull422     fun addUniqueIdAssociationByPort_verifyAssociations() {
423         // Overall goal is to have 2 displays and verify that events from the InputDevice are
424         // sent only to the view that is on the associated display.
425         // So, associate the InputDevice with display 1, then send and verify KeyEvents.
426         // Then remove associations, then associate the InputDevice with display 2, then send
427         // and verify commands.
428 
429         // Make 2 virtual displays with some mock SurfaceViews
430         val mockSurfaceView1 = mock(SurfaceView::class.java)
431         val mockSurfaceView2 = mock(SurfaceView::class.java)
432         val mockSurfaceHolder1 = mock(SurfaceHolder::class.java)
433         `when`(mockSurfaceView1.holder).thenReturn(mockSurfaceHolder1)
434         val mockSurfaceHolder2 = mock(SurfaceHolder::class.java)
435         `when`(mockSurfaceView2.holder).thenReturn(mockSurfaceHolder2)
436 
437         val virtualDisplays = createVirtualDisplays(2)
438 
439         // Simulate an InputDevice
440         val inputDevice = createInputDevice()
441 
442         // Associate input device with display
443         service.addUniqueIdAssociationByPort(
444                 inputDevice.name,
445                 virtualDisplays[0].display.displayId.toString()
446         )
447 
448         // Simulate 2 different KeyEvents
449         val downEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_DOWN)
450         val upEvent = createKeycodeAEvent(inputDevice, KeyEvent.ACTION_UP)
451 
452         // Create a mock OnKeyListener object
453         val mockOnKeyListener = mock(OnKeyListener::class.java)
454 
455         // Verify that the event went to Display 1 not Display 2
456         service.injectInputEvent(downEvent, InputEventInjectionSync.NONE)
457 
458         // Call the onKey method on the mock OnKeyListener object
459         mockOnKeyListener.onKey(mockSurfaceView1, /* keyCode= */ KeyEvent.KEYCODE_A, downEvent)
460         mockOnKeyListener.onKey(mockSurfaceView2, /* keyCode= */ KeyEvent.KEYCODE_A, upEvent)
461 
462         // Verify that the onKey method was called with the expected arguments
463         verify(mockOnKeyListener).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, downEvent)
464         verify(mockOnKeyListener, never()).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, downEvent)
465 
466         // Remove association
467         service.removeUniqueIdAssociationByPort(inputDevice.name)
468 
469         // Associate with Display 2
470         service.addUniqueIdAssociationByPort(
471                 inputDevice.name,
472                 virtualDisplays[1].display.displayId.toString()
473         )
474 
475         // Simulate a KeyEvent
476         service.injectInputEvent(upEvent, InputEventInjectionSync.NONE)
477 
478         // Verify that the event went to Display 2 not Display 1
479         verify(mockOnKeyListener).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, upEvent)
480         verify(mockOnKeyListener, never()).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, upEvent)
481     }
482 
483     @Test
484     @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
handleKeyGestures_keyboardBacklightnull485     fun handleKeyGestures_keyboardBacklight() {
486         service.systemRunning()
487 
488         val backlightDownEvent = createKeyEvent(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN)
489         service.interceptKeyBeforeDispatching(null, backlightDownEvent, /* policyFlags = */0)
490         verify(kbdController).decrementKeyboardBacklight(anyInt())
491 
492         val backlightUpEvent = createKeyEvent(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP)
493         service.interceptKeyBeforeDispatching(null, backlightUpEvent, /* policyFlags = */0)
494         verify(kbdController).incrementKeyboardBacklight(anyInt())
495     }
496 
497     @Test
498     @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
handleKeyGestures_toggleCapsLocknull499     fun handleKeyGestures_toggleCapsLock() {
500         service.systemRunning()
501 
502         val metaDownEvent = createKeyEvent(KeyEvent.KEYCODE_META_LEFT)
503         service.interceptKeyBeforeDispatching(null, metaDownEvent, /* policyFlags = */0)
504         val altDownEvent =
505             createKeyEvent(KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.META_META_ON, KeyEvent.ACTION_DOWN)
506         service.interceptKeyBeforeDispatching(null, altDownEvent, /* policyFlags = */0)
507         val altUpEvent =
508             createKeyEvent(KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.META_META_ON, KeyEvent.ACTION_UP)
509         service.interceptKeyBeforeDispatching(null, altUpEvent, /* policyFlags = */0)
510 
511         verify(native).toggleCapsLock(anyInt())
512     }
513 
overrideSendActionKeyEventsToFocusedWindownull514     fun overrideSendActionKeyEventsToFocusedWindow(
515         hasPermission: Boolean,
516         hasPrivateFlag: Boolean
517     ) {
518         ExtendedMockito.doReturn(
519             if (hasPermission) {
520                 PermissionChecker.PERMISSION_GRANTED
521             } else {
522                 PermissionChecker.PERMISSION_HARD_DENIED
523             }
524         ).`when` {
525             PermissionChecker.checkPermissionForDataDelivery(
526                 any(),
527                 eq(Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW),
528                 anyInt(),
529                 anyInt(),
530                 any(),
531                 any(),
532                 any()
533             )
534         }
535 
536         val info = KeyInterceptionInfo(
537             /* type = */0,
538             if (hasPrivateFlag) {
539                 WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS
540             } else {
541                 0
542             },
543             "title",
544             /* uid = */0
545         )
546         whenever(windowManagerInternal.getKeyInterceptionInfoFromToken(any())).thenReturn(info)
547     }
548 
createKeyEventnull549     private fun createKeyEvent(
550         keycode: Int,
551         modifierState: Int = 0,
552         action: Int = KeyEvent.ACTION_DOWN
553     ): KeyEvent {
554         return KeyEvent(
555             /* downTime = */0,
556             /* eventTime = */0,
557             action,
558             keycode,
559             /* repeat = */0,
560             modifierState,
561             KeyCharacterMap.VIRTUAL_KEYBOARD,
562             /* scancode = */0,
563             /* flags = */0,
564             InputDevice.SOURCE_KEYBOARD
565         )
566     }
567 }
568 
whenevernull569 private fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall)
570