1 /* 2 * Copyright (C) 2019 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.car; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.ArgumentMatchers.any; 22 import static org.mockito.ArgumentMatchers.anyInt; 23 import static org.mockito.ArgumentMatchers.anyLong; 24 import static org.mockito.ArgumentMatchers.eq; 25 import static org.mockito.ArgumentMatchers.isNull; 26 import static org.mockito.Mockito.atLeast; 27 import static org.mockito.Mockito.clearInvocations; 28 import static org.mockito.Mockito.doNothing; 29 import static org.mockito.Mockito.doReturn; 30 import static org.mockito.Mockito.ignoreStubs; 31 import static org.mockito.Mockito.mock; 32 import static org.mockito.Mockito.never; 33 import static org.mockito.Mockito.verify; 34 import static org.mockito.Mockito.verifyNoMoreInteractions; 35 import static org.mockito.Mockito.when; 36 37 import android.car.CarProjectionManager; 38 import android.car.input.CarInputHandlingService.InputFilter; 39 import android.car.input.ICarInputListener; 40 import android.content.ComponentName; 41 import android.content.Context; 42 import android.content.Intent; 43 import android.net.Uri; 44 import android.os.Bundle; 45 import android.os.Handler; 46 import android.os.Looper; 47 import android.os.Message; 48 import android.os.RemoteException; 49 import android.os.SystemClock; 50 import android.os.UserHandle; 51 import android.service.voice.VoiceInteractionSession; 52 import android.telecom.TelecomManager; 53 import android.view.KeyEvent; 54 55 import androidx.test.core.app.ApplicationProvider; 56 import androidx.test.runner.AndroidJUnit4; 57 58 import com.android.car.hal.InputHalService; 59 import com.android.internal.app.AssistUtils; 60 61 import com.google.common.collect.Range; 62 63 import org.junit.Before; 64 import org.junit.Rule; 65 import org.junit.Test; 66 import org.junit.runner.RunWith; 67 import org.mockito.ArgumentCaptor; 68 import org.mockito.Mock; 69 import org.mockito.Spy; 70 import org.mockito.junit.MockitoJUnit; 71 import org.mockito.junit.MockitoRule; 72 73 import java.util.BitSet; 74 import java.util.function.IntSupplier; 75 import java.util.function.Supplier; 76 77 @RunWith(AndroidJUnit4.class) 78 public class CarInputServiceTest { 79 @Rule public MockitoRule rule = MockitoJUnit.rule(); 80 81 @Mock InputHalService mInputHalService; 82 @Mock TelecomManager mTelecomManager; 83 @Mock AssistUtils mAssistUtils; 84 @Mock CarInputService.KeyEventListener mDefaultMainListener; 85 @Mock Supplier<String> mLastCallSupplier; 86 @Mock IntSupplier mLongPressDelaySupplier; 87 88 @Spy Context mContext = ApplicationProvider.getApplicationContext(); 89 @Spy Handler mHandler = new Handler(Looper.getMainLooper()); 90 91 private CarInputService mCarInputService; 92 93 @Before setUp()94 public void setUp() { 95 mCarInputService = new CarInputService(mContext, mInputHalService, mHandler, 96 mTelecomManager, mAssistUtils, mDefaultMainListener, mLastCallSupplier, 97 /* customInputServiceComponent= */ null, mLongPressDelaySupplier); 98 99 when(mInputHalService.isKeyInputSupported()).thenReturn(true); 100 mCarInputService.init(); 101 102 // Delay Handler callbacks until flushHandler() is called. 103 doReturn(true).when(mHandler).sendMessageAtTime(any(), anyLong()); 104 } 105 106 @Test ordinaryEvents_onMainDisplay_routedToInputManager()107 public void ordinaryEvents_onMainDisplay_routedToInputManager() { 108 KeyEvent event = send(Key.DOWN, KeyEvent.KEYCODE_ENTER, Display.MAIN); 109 110 verify(mDefaultMainListener).onKeyEvent(event); 111 } 112 113 @Test ordinaryEvents_onInstrumentClusterDisplay_notRoutedToInputManager()114 public void ordinaryEvents_onInstrumentClusterDisplay_notRoutedToInputManager() { 115 send(Key.DOWN, KeyEvent.KEYCODE_ENTER, Display.INSTRUMENT_CLUSTER); 116 117 verify(mDefaultMainListener, never()).onKeyEvent(any()); 118 } 119 120 @Test ordinaryEvents_onInstrumentClusterDisplay_routedToListener()121 public void ordinaryEvents_onInstrumentClusterDisplay_routedToListener() { 122 CarInputService.KeyEventListener listener = mock(CarInputService.KeyEventListener.class); 123 mCarInputService.setInstrumentClusterKeyListener(listener); 124 125 KeyEvent event = send(Key.DOWN, KeyEvent.KEYCODE_ENTER, Display.INSTRUMENT_CLUSTER); 126 verify(listener).onKeyEvent(event); 127 } 128 129 @Test customEventHandler_capturesRegisteredEvents_ignoresUnregisteredEvents()130 public void customEventHandler_capturesRegisteredEvents_ignoresUnregisteredEvents() 131 throws RemoteException { 132 KeyEvent event; 133 ICarInputListener listener = registerInputListener( 134 new InputFilter(KeyEvent.KEYCODE_ENTER, InputHalService.DISPLAY_MAIN), 135 new InputFilter(KeyEvent.KEYCODE_ENTER, InputHalService.DISPLAY_INSTRUMENT_CLUSTER), 136 new InputFilter(KeyEvent.KEYCODE_MENU, InputHalService.DISPLAY_MAIN)); 137 138 CarInputService.KeyEventListener instrumentClusterListener = 139 mock(CarInputService.KeyEventListener.class); 140 mCarInputService.setInstrumentClusterKeyListener(instrumentClusterListener); 141 142 event = send(Key.DOWN, KeyEvent.KEYCODE_ENTER, Display.MAIN); 143 verify(listener).onKeyEvent(event, InputHalService.DISPLAY_MAIN); 144 verify(mDefaultMainListener, never()).onKeyEvent(any()); 145 146 event = send(Key.DOWN, KeyEvent.KEYCODE_ENTER, Display.INSTRUMENT_CLUSTER); 147 verify(listener).onKeyEvent(event, InputHalService.DISPLAY_INSTRUMENT_CLUSTER); 148 verify(instrumentClusterListener, never()).onKeyEvent(any()); 149 150 event = send(Key.DOWN, KeyEvent.KEYCODE_MENU, Display.MAIN); 151 verify(listener).onKeyEvent(event, InputHalService.DISPLAY_MAIN); 152 verify(mDefaultMainListener, never()).onKeyEvent(any()); 153 154 event = send(Key.DOWN, KeyEvent.KEYCODE_MENU, Display.INSTRUMENT_CLUSTER); 155 verify(listener, never()).onKeyEvent(event, InputHalService.DISPLAY_INSTRUMENT_CLUSTER); 156 verify(instrumentClusterListener).onKeyEvent(event); 157 } 158 159 @Test voiceKey_shortPress_withRegisteredEventHandler_triggersEventHandler()160 public void voiceKey_shortPress_withRegisteredEventHandler_triggersEventHandler() { 161 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 162 registerProjectionKeyEventHandler( 163 CarProjectionManager.KEY_EVENT_VOICE_SEARCH_SHORT_PRESS_KEY_UP); 164 165 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 166 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 167 168 verify(eventHandler) 169 .onKeyEvent(CarProjectionManager.KEY_EVENT_VOICE_SEARCH_SHORT_PRESS_KEY_UP); 170 } 171 172 @Test voiceKey_longPress_withRegisteredEventHandler_triggersEventHandler()173 public void voiceKey_longPress_withRegisteredEventHandler_triggersEventHandler() { 174 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 175 registerProjectionKeyEventHandler( 176 CarProjectionManager.KEY_EVENT_VOICE_SEARCH_SHORT_PRESS_KEY_UP, 177 CarProjectionManager.KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_DOWN); 178 179 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 180 verify(eventHandler, never()).onKeyEvent(anyInt()); 181 182 // Simulate the long-press timer expiring. 183 flushHandler(); 184 verify(eventHandler) 185 .onKeyEvent(CarProjectionManager.KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_DOWN); 186 187 // Ensure that the short-press handler is *not* called. 188 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 189 flushHandler(); 190 verify(eventHandler, never()) 191 .onKeyEvent(CarProjectionManager.KEY_EVENT_VOICE_SEARCH_SHORT_PRESS_KEY_UP); 192 } 193 194 @Test voiceKey_shortPress_withoutRegisteredEventHandler_triggersAssistUtils()195 public void voiceKey_shortPress_withoutRegisteredEventHandler_triggersAssistUtils() { 196 when(mAssistUtils.getAssistComponentForUser(anyInt())) 197 .thenReturn(new ComponentName("pkg", "cls")); 198 199 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 200 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 201 202 ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); 203 verify(mAssistUtils).showSessionForActiveService( 204 bundleCaptor.capture(), 205 eq(VoiceInteractionSession.SHOW_SOURCE_PUSH_TO_TALK), 206 any(), 207 isNull()); 208 assertThat(bundleCaptor.getValue().getBoolean(CarInputService.EXTRA_CAR_PUSH_TO_TALK)) 209 .isTrue(); 210 } 211 212 @Test voiceKey_longPress_withoutRegisteredEventHandler_triggersAssistUtils()213 public void voiceKey_longPress_withoutRegisteredEventHandler_triggersAssistUtils() { 214 when(mAssistUtils.getAssistComponentForUser(anyInt())) 215 .thenReturn(new ComponentName("pkg", "cls")); 216 217 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 218 flushHandler(); 219 220 ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class); 221 verify(mAssistUtils).showSessionForActiveService( 222 bundleCaptor.capture(), 223 eq(VoiceInteractionSession.SHOW_SOURCE_PUSH_TO_TALK), 224 any(), 225 isNull()); 226 assertThat(bundleCaptor.getValue().getBoolean(CarInputService.EXTRA_CAR_PUSH_TO_TALK)) 227 .isTrue(); 228 229 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 230 verifyNoMoreInteractions(ignoreStubs(mAssistUtils)); 231 } 232 233 @Test voiceKey_keyDown_withEventHandler_triggersEventHandler()234 public void voiceKey_keyDown_withEventHandler_triggersEventHandler() { 235 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 236 registerProjectionKeyEventHandler( 237 CarProjectionManager.KEY_EVENT_VOICE_SEARCH_KEY_DOWN); 238 239 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 240 241 verify(eventHandler).onKeyEvent(CarProjectionManager.KEY_EVENT_VOICE_SEARCH_KEY_DOWN); 242 } 243 244 @Test voiceKey_keyUp_afterLongPress_withEventHandler_triggersEventHandler()245 public void voiceKey_keyUp_afterLongPress_withEventHandler_triggersEventHandler() { 246 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 247 registerProjectionKeyEventHandler( 248 CarProjectionManager.KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_UP); 249 250 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 251 flushHandler(); 252 verify(eventHandler, never()) 253 .onKeyEvent(CarProjectionManager.KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_UP); 254 255 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 256 verify(eventHandler) 257 .onKeyEvent(CarProjectionManager.KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_UP); 258 } 259 260 @Test voiceKey_repeatedEvents_ignored()261 public void voiceKey_repeatedEvents_ignored() { 262 // Pressing a key starts the long-press timer. 263 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 264 verify(mHandler).sendMessageAtTime(any(), anyLong()); 265 clearInvocations(mHandler); 266 267 // Repeated KEY_DOWN events don't reset the timer. 268 sendWithRepeat(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN, 1); 269 verify(mHandler, never()).sendMessageAtTime(any(), anyLong()); 270 } 271 272 @Test callKey_shortPress_withoutEventHandler_launchesDialer()273 public void callKey_shortPress_withoutEventHandler_launchesDialer() { 274 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 275 276 doNothing().when(mContext).startActivityAsUser(any(), any(), any()); 277 278 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 279 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 280 281 verify(mContext).startActivityAsUser( 282 intentCaptor.capture(), any(), eq(UserHandle.CURRENT_OR_SELF)); 283 assertThat(intentCaptor.getValue().getAction()).isEqualTo(Intent.ACTION_DIAL); 284 } 285 286 @Test callKey_shortPress_withoutEventHandler_whenCallRinging_answersCall()287 public void callKey_shortPress_withoutEventHandler_whenCallRinging_answersCall() { 288 when(mTelecomManager.isRinging()).thenReturn(true); 289 290 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 291 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 292 293 verify(mTelecomManager).acceptRingingCall(); 294 // Ensure default handler does not run. 295 verify(mContext, never()).startActivityAsUser(any(), any(), any()); 296 } 297 298 @Test callKey_shortPress_withEventHandler_triggersEventHandler()299 public void callKey_shortPress_withEventHandler_triggersEventHandler() { 300 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 301 registerProjectionKeyEventHandler( 302 CarProjectionManager.KEY_EVENT_CALL_SHORT_PRESS_KEY_UP); 303 304 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 305 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 306 307 verify(eventHandler).onKeyEvent(CarProjectionManager.KEY_EVENT_CALL_SHORT_PRESS_KEY_UP); 308 // Ensure default handlers do not run. 309 verify(mTelecomManager, never()).acceptRingingCall(); 310 verify(mContext, never()).startActivityAsUser(any(), any(), any()); 311 } 312 313 @Test callKey_shortPress_withEventHandler_whenCallRinging_answersCall()314 public void callKey_shortPress_withEventHandler_whenCallRinging_answersCall() { 315 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 316 registerProjectionKeyEventHandler( 317 CarProjectionManager.KEY_EVENT_CALL_SHORT_PRESS_KEY_UP); 318 when(mTelecomManager.isRinging()).thenReturn(true); 319 320 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 321 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 322 323 verify(mTelecomManager).acceptRingingCall(); 324 verify(eventHandler, never()).onKeyEvent(anyInt()); 325 } 326 327 @Test callKey_longPress_withoutEventHandler_redialsLastCall()328 public void callKey_longPress_withoutEventHandler_redialsLastCall() { 329 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 330 331 when(mLastCallSupplier.get()).thenReturn("1234567890"); 332 doNothing().when(mContext).startActivityAsUser(any(), any(), any()); 333 334 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 335 flushHandler(); 336 337 verify(mContext).startActivityAsUser( 338 intentCaptor.capture(), any(), eq(UserHandle.CURRENT_OR_SELF)); 339 340 Intent intent = intentCaptor.getValue(); 341 assertThat(intent.getAction()).isEqualTo(Intent.ACTION_CALL); 342 assertThat(intent.getData()).isEqualTo(Uri.parse("tel:1234567890")); 343 344 clearInvocations(mContext); 345 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 346 verify(mContext, never()).startActivityAsUser(any(), any(), any()); 347 } 348 349 @Test callKey_longPress_withoutEventHandler_withNoLastCall_doesNothing()350 public void callKey_longPress_withoutEventHandler_withNoLastCall_doesNothing() { 351 when(mLastCallSupplier.get()).thenReturn(""); 352 353 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 354 flushHandler(); 355 356 verify(mContext, never()).startActivityAsUser(any(), any(), any()); 357 } 358 359 @Test callKey_longPress_withoutEventHandler_whenCallRinging_answersCall()360 public void callKey_longPress_withoutEventHandler_whenCallRinging_answersCall() { 361 when(mTelecomManager.isRinging()).thenReturn(true); 362 363 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 364 flushHandler(); 365 366 verify(mTelecomManager).acceptRingingCall(); 367 368 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 369 // Ensure that default handler does not run, either after accepting ringing call, 370 // or as a result of key-up. 371 verify(mContext, never()).startActivityAsUser(any(), any(), any()); 372 } 373 374 @Test callKey_longPress_withEventHandler_triggersEventHandler()375 public void callKey_longPress_withEventHandler_triggersEventHandler() { 376 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 377 registerProjectionKeyEventHandler( 378 CarProjectionManager.KEY_EVENT_CALL_LONG_PRESS_KEY_DOWN); 379 380 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 381 flushHandler(); 382 383 verify(eventHandler).onKeyEvent(CarProjectionManager.KEY_EVENT_CALL_LONG_PRESS_KEY_DOWN); 384 verify(mContext, never()).startActivityAsUser(any(), any(), any()); 385 } 386 387 @Test callKey_longPress_withEventHandler_whenCallRinging_answersCall()388 public void callKey_longPress_withEventHandler_whenCallRinging_answersCall() { 389 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 390 registerProjectionKeyEventHandler( 391 CarProjectionManager.KEY_EVENT_CALL_LONG_PRESS_KEY_DOWN); 392 when(mTelecomManager.isRinging()).thenReturn(true); 393 394 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 395 flushHandler(); 396 397 verify(mTelecomManager).acceptRingingCall(); 398 399 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 400 // Ensure that event handler does not run, either after accepting ringing call, 401 // or as a result of key-up. 402 verify(eventHandler, never()).onKeyEvent(anyInt()); 403 } 404 405 @Test callKey_keyDown_withEventHandler_triggersEventHandler()406 public void callKey_keyDown_withEventHandler_triggersEventHandler() { 407 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 408 registerProjectionKeyEventHandler( 409 CarProjectionManager.KEY_EVENT_CALL_KEY_DOWN); 410 411 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 412 413 verify(eventHandler).onKeyEvent(CarProjectionManager.KEY_EVENT_CALL_KEY_DOWN); 414 } 415 416 @Test callKey_keyUp_afterLongPress_withEventHandler_triggersEventHandler()417 public void callKey_keyUp_afterLongPress_withEventHandler_triggersEventHandler() { 418 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 419 registerProjectionKeyEventHandler( 420 CarProjectionManager.KEY_EVENT_CALL_LONG_PRESS_KEY_UP); 421 422 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 423 flushHandler(); 424 verify(eventHandler, never()) 425 .onKeyEvent(CarProjectionManager.KEY_EVENT_CALL_LONG_PRESS_KEY_UP); 426 427 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 428 verify(eventHandler).onKeyEvent(CarProjectionManager.KEY_EVENT_CALL_LONG_PRESS_KEY_UP); 429 } 430 431 @Test callKey_repeatedEvents_ignored()432 public void callKey_repeatedEvents_ignored() { 433 // Pressing a key starts the long-press timer. 434 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 435 verify(mHandler).sendMessageAtTime(any(), anyLong()); 436 clearInvocations(mHandler); 437 438 // Repeated KEY_DOWN events don't reset the timer. 439 sendWithRepeat(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN, 1); 440 verify(mHandler, never()).sendMessageAtTime(any(), anyLong()); 441 } 442 443 @Test longPressDelay_obeysValueFromSystem()444 public void longPressDelay_obeysValueFromSystem() { 445 final int systemDelay = 4242; 446 447 when(mLongPressDelaySupplier.getAsInt()).thenReturn(systemDelay); 448 ArgumentCaptor<Long> timeCaptor = ArgumentCaptor.forClass(long.class); 449 450 long then = SystemClock.uptimeMillis(); 451 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 452 long now = SystemClock.uptimeMillis(); 453 454 verify(mHandler).sendMessageAtTime(any(), timeCaptor.capture()); 455 456 // The message time must be the expected delay time (as provided by the supplier) after 457 // the time the message was sent to the handler. We don't know that exact time, but we 458 // can put a bound on it - it's no sooner than immediately before the call to send(), and no 459 // later than immediately afterwards. Check to make sure the actual observed message time is 460 // somewhere in the valid range. 461 462 assertThat(timeCaptor.getValue()).isIn(Range.closed(then + systemDelay, now + systemDelay)); 463 } 464 465 private enum Key {DOWN, UP} 466 467 private enum Display {MAIN, INSTRUMENT_CLUSTER} 468 send(Key action, int keyCode, Display display)469 private KeyEvent send(Key action, int keyCode, Display display) { 470 return sendWithRepeat(action, keyCode, display, 0); 471 } 472 sendWithRepeat(Key action, int keyCode, Display display, int repeatCount)473 private KeyEvent sendWithRepeat(Key action, int keyCode, Display display, int repeatCount) { 474 KeyEvent event = new KeyEvent( 475 /* downTime= */ 0L, 476 /* eventTime= */ 0L, 477 action == Key.DOWN ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP, 478 keyCode, 479 repeatCount); 480 mCarInputService.onKeyEvent( 481 event, 482 display == Display.MAIN 483 ? InputHalService.DISPLAY_MAIN 484 : InputHalService.DISPLAY_INSTRUMENT_CLUSTER); 485 return event; 486 } 487 registerInputListener(InputFilter... handledKeys)488 private ICarInputListener registerInputListener(InputFilter... handledKeys) { 489 ICarInputListener listener = mock(ICarInputListener.class); 490 mCarInputService.mCarInputListener = listener; 491 mCarInputService.setHandledKeys(handledKeys); 492 return listener; 493 } 494 registerProjectionKeyEventHandler( int... events)495 private CarProjectionManager.ProjectionKeyEventHandler registerProjectionKeyEventHandler( 496 int... events) { 497 BitSet eventSet = new BitSet(); 498 for (int event : events) { 499 eventSet.set(event); 500 } 501 502 CarProjectionManager.ProjectionKeyEventHandler projectionKeyEventHandler = 503 mock(CarProjectionManager.ProjectionKeyEventHandler.class); 504 mCarInputService.setProjectionKeyEventHandler(projectionKeyEventHandler, eventSet); 505 return projectionKeyEventHandler; 506 } 507 flushHandler()508 private void flushHandler() { 509 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 510 511 verify(mHandler, atLeast(0)).sendMessageAtTime(messageCaptor.capture(), anyLong()); 512 513 for (Message message : messageCaptor.getAllValues()) { 514 mHandler.dispatchMessage(message); 515 } 516 517 clearInvocations(mHandler); 518 } 519 } 520