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 android.car.CarOccupantZoneManager.DisplayTypeEnum; 20 import static android.car.input.CustomInputEvent.INPUT_CODE_F1; 21 import static android.view.Display.DEFAULT_DISPLAY; 22 import static android.view.Display.INVALID_DISPLAY; 23 24 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; 25 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 26 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 27 28 import static com.google.common.truth.Truth.assertThat; 29 import static com.google.common.truth.Truth.assertWithMessage; 30 31 import static org.mockito.ArgumentMatchers.any; 32 import static org.mockito.ArgumentMatchers.anyBoolean; 33 import static org.mockito.ArgumentMatchers.anyInt; 34 import static org.mockito.ArgumentMatchers.anyLong; 35 import static org.mockito.ArgumentMatchers.eq; 36 import static org.mockito.ArgumentMatchers.same; 37 import static org.mockito.Mockito.atLeast; 38 import static org.mockito.Mockito.clearInvocations; 39 import static org.mockito.Mockito.doNothing; 40 import static org.mockito.Mockito.mock; 41 import static org.mockito.Mockito.never; 42 import static org.mockito.Mockito.times; 43 import static org.mockito.Mockito.when; 44 45 import android.bluetooth.BluetoothAdapter; 46 import android.bluetooth.BluetoothManager; 47 import android.car.CarOccupantZoneManager; 48 import android.car.CarOccupantZoneManager.OccupantZoneInfo; 49 import android.car.CarProjectionManager; 50 import android.car.VehicleAreaSeat; 51 import android.car.builtin.util.AssistUtilsHelper; 52 import android.car.builtin.util.AssistUtilsHelper.VoiceInteractionSessionShowCallbackHelper; 53 import android.car.drivingstate.CarDrivingStateEvent; 54 import android.car.feature.Flags; 55 import android.car.input.CarInputManager; 56 import android.car.input.CustomInputEvent; 57 import android.car.input.ICarInputCallback; 58 import android.car.input.RotaryEvent; 59 import android.car.test.mocks.AbstractExtendedMockitoTestCase; 60 import android.content.Context; 61 import android.content.Intent; 62 import android.content.pm.PackageManager; 63 import android.content.res.Resources; 64 import android.net.Uri; 65 import android.os.Handler; 66 import android.os.Looper; 67 import android.os.Message; 68 import android.os.SystemClock; 69 import android.os.UserHandle; 70 import android.platform.test.annotations.RequiresFlagsEnabled; 71 import android.platform.test.flag.junit.CheckFlagsRule; 72 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 73 import android.provider.Settings; 74 import android.telecom.TelecomManager; 75 import android.view.KeyEvent; 76 import android.view.MotionEvent; 77 78 import androidx.test.core.app.ApplicationProvider; 79 80 import com.android.car.audio.CarAudioService; 81 import com.android.car.bluetooth.CarBluetoothService; 82 import com.android.car.hal.InputHalService; 83 import com.android.car.power.CarPowerManagementService; 84 import com.android.car.systeminterface.SystemInterface; 85 import com.android.car.user.CarUserService; 86 87 import com.google.common.collect.Range; 88 89 import org.junit.After; 90 import org.junit.Assert; 91 import org.junit.Before; 92 import org.junit.Rule; 93 import org.junit.Test; 94 import org.mockito.ArgumentCaptor; 95 import org.mockito.Mock; 96 import org.mockito.Spy; 97 98 import java.util.BitSet; 99 import java.util.Collections; 100 import java.util.List; 101 import java.util.function.BooleanSupplier; 102 import java.util.function.IntSupplier; 103 import java.util.function.Supplier; 104 105 public final class CarInputServiceTest extends AbstractExtendedMockitoTestCase { 106 107 @Mock InputHalService mInputHalService; 108 @Mock TelecomManager mTelecomManager; 109 @Mock CarInputService.KeyEventListener mDefaultKeyEventMainListener; 110 @Mock CarInputService.MotionEventListener mDefaultMotionEventMainListener; 111 @Mock CarInputService.KeyEventListener mInstrumentClusterKeyListener; 112 @Mock Supplier<String> mLastCallSupplier; 113 @Mock IntSupplier mLongPressDelaySupplier; 114 @Mock BooleanSupplier mShouldCallButtonEndOngoingCallSupplier; 115 @Mock InputCaptureClientController mCaptureController; 116 @Mock CarOccupantZoneService mCarOccupantZoneService; 117 @Mock CarBluetoothService mCarBluetoothService; 118 @Mock CarDrivingStateService mMockCarDrivingStateService; 119 @Mock CarPowerManagementService mCarPowerManagementService; 120 @Mock SystemInterface mSystemInterface; 121 @Mock CarAudioService mCarAudioService; 122 @Mock CarMediaService mCarMediaService; 123 @Mock BluetoothManager mMockBluetoothManager; 124 @Mock BluetoothAdapter mMockBluetoothAdapter; 125 126 @Spy Context mContext = ApplicationProvider.getApplicationContext(); 127 @Mock private Resources mMockResources; 128 @Spy Handler mHandler = new Handler(Looper.getMainLooper()); 129 130 @Mock CarUserService mCarUserService; 131 private CarInputService mCarInputService; 132 133 private static final int DRIVER_USER_ID = 111; 134 private static final int PASSENGER_USER_ID = 112; 135 136 private static final int DRIVER_DISPLAY_ID = 121; 137 private static final int PASSENGER_DISPLAY_ID = 122; 138 139 private static final int DRIVER_ZONE_ID = 131; 140 private static final int PASSENGER_ZONE_ID = 132; 141 142 private static final int UNKNOWN_SEAT = VehicleAreaSeat.SEAT_UNKNOWN; 143 private static final int DRIVER_SEAT = VehicleAreaSeat.SEAT_ROW_1_LEFT; 144 private static final int PASSENGER_SEAT = VehicleAreaSeat.SEAT_ROW_1_RIGHT; 145 146 @Rule 147 public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 148 149 // CarInputService#sDefaultShowCallback() prints out some Slog message which can be conflicted 150 // with AbstractExtendedMockitoTestCase#interceptWtfCalls (b/294138315). 151 private static final VoiceInteractionSessionShowCallbackHelper sShowCallback = 152 new VoiceInteractionSessionShowCallbackHelper() { 153 @Override public void onFailed() { 154 // No op 155 } 156 @Override public void onShown() { 157 // No op 158 } 159 }; 160 CarInputServiceTest()161 public CarInputServiceTest() { 162 super(CarInputService.TAG); 163 } 164 165 @Before setUp()166 public void setUp() { 167 mCarInputService = new CarInputService(mContext, mInputHalService, mCarUserService, 168 mCarOccupantZoneService, mCarBluetoothService, mCarPowerManagementService, 169 mSystemInterface, mHandler, mTelecomManager, mDefaultKeyEventMainListener, 170 mDefaultMotionEventMainListener, mLastCallSupplier, mLongPressDelaySupplier, 171 mShouldCallButtonEndOngoingCallSupplier, mCaptureController, 172 sShowCallback); 173 174 mCarInputService.setInstrumentClusterKeyListener(mInstrumentClusterKeyListener); 175 176 when(mInputHalService.isKeyInputSupported()).thenReturn(true); 177 178 // Delay Handler callbacks until flushHandler() is called. 179 doReturn(true).when(mHandler).sendMessageAtTime(any(), anyLong()); 180 181 when(mShouldCallButtonEndOngoingCallSupplier.getAsBoolean()).thenReturn(false); 182 183 when(mContext.getResources()).thenReturn(mMockResources); 184 185 mockEnableLongPressBluetoothPairingProperty(false); 186 187 setUpCarOccupantZoneService(); 188 setUpService(); 189 mCarInputService.init(); 190 } 191 192 @Override onSessionBuilder(CustomMockitoSessionBuilder session)193 protected void onSessionBuilder(CustomMockitoSessionBuilder session) { 194 session.spyStatic(AssistUtilsHelper.class); 195 session.spyStatic(CarServiceUtils.class); 196 } 197 setUpCarOccupantZoneService()198 private void setUpCarOccupantZoneService() { 199 when(mCarOccupantZoneService.getDriverSeat()).thenReturn(DRIVER_SEAT); 200 201 when(mCarOccupantZoneService.getOccupantZoneIdForSeat(eq(DRIVER_SEAT))) 202 .thenReturn(DRIVER_ZONE_ID); 203 when(mCarOccupantZoneService.getOccupantZoneIdForSeat(eq(PASSENGER_SEAT))) 204 .thenReturn(PASSENGER_ZONE_ID); 205 206 when(mCarOccupantZoneService.getUserForOccupant(eq(DRIVER_ZONE_ID))) 207 .thenReturn(DRIVER_USER_ID); 208 when(mCarOccupantZoneService.getUserForOccupant(eq(PASSENGER_ZONE_ID))) 209 .thenReturn(PASSENGER_USER_ID); 210 211 when(mCarOccupantZoneService.getDisplayForOccupant(eq(DRIVER_ZONE_ID), 212 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN))).thenReturn(DRIVER_DISPLAY_ID); 213 when(mCarOccupantZoneService.getDisplayForOccupant(eq(PASSENGER_ZONE_ID), 214 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN))).thenReturn(PASSENGER_DISPLAY_ID); 215 } 216 setUpService()217 private void setUpService() { 218 CarLocalServices.removeServiceForTest(CarAudioService.class); 219 CarLocalServices.addService(CarAudioService.class, mCarAudioService); 220 CarLocalServices.removeServiceForTest(CarMediaService.class); 221 CarLocalServices.addService(CarMediaService.class, mCarMediaService); 222 CarLocalServices.removeServiceForTest(CarDrivingStateService.class); 223 CarLocalServices.addService(CarDrivingStateService.class, mMockCarDrivingStateService); 224 225 } 226 227 @After tearDown()228 public void tearDown() { 229 if (mCarInputService != null) { 230 mCarInputService.release(); 231 } 232 233 CarLocalServices.removeServiceForTest(CarAudioService.class); 234 CarLocalServices.removeServiceForTest(CarMediaService.class); 235 CarLocalServices.removeServiceForTest(CarDrivingStateService.class); 236 } 237 238 @Test testConstantValueMatching()239 public void testConstantValueMatching() { 240 assertWithMessage( 241 "CarInputService.LONG_PRESS_TIMEOUT ('%s') must match the string defined in " 242 + "Settings.Secure.LONG_PRESS_TIMEOUT", 243 CarInputService.LONG_PRESS_TIMEOUT).that( 244 CarInputService.LONG_PRESS_TIMEOUT).isEqualTo( 245 Settings.Secure.LONG_PRESS_TIMEOUT); 246 } 247 248 @Test testOnRotaryEvent_injectingRotaryNavigationEvent()249 public void testOnRotaryEvent_injectingRotaryNavigationEvent() { 250 RotaryEvent event = new RotaryEvent( 251 /* inputType= */ CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, 252 /* clockwise= */ true, 253 /* uptimeMillisForClicks= */ new long[]{1, 1}); 254 when(mCaptureController.onRotaryEvent( 255 same(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), same(event))).thenReturn(true); 256 when(mCaptureController.onKeyEvent(anyInt(), any(KeyEvent.class))).thenReturn(true); 257 258 mCarInputService.onRotaryEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN); 259 260 // Since mCaptureController processed RotaryEvent, then no KeyEvent was generated or 261 // processed 262 verify(mCarOccupantZoneService, never()).getDisplayIdForDriver(anyInt()); 263 verify(mCaptureController, never()).onKeyEvent(anyInt(), any(KeyEvent.class)); 264 verify(mDefaultKeyEventMainListener, never()) 265 .onKeyEvent(any(KeyEvent.class), anyInt(), anyInt()); 266 } 267 268 @Test testOnRotaryEvent_injectingRotaryVolumeEvent()269 public void testOnRotaryEvent_injectingRotaryVolumeEvent() { 270 RotaryEvent event = new RotaryEvent( 271 /* inputType= */ CarInputManager.INPUT_TYPE_ROTARY_VOLUME, 272 /* clockwise= */ true, 273 /* uptimeMillisForClicks= */ new long[]{1, 1}); 274 when(mCaptureController.onRotaryEvent( 275 same(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), same(event))).thenReturn(false); 276 when(mCaptureController.onKeyEvent(anyInt(), any(KeyEvent.class))).thenReturn(true); 277 278 mCarInputService.onRotaryEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN); 279 280 // Since mCaptureController processed RotaryEvent, then KeyEvent was generated or 281 // processed 282 int numberOfGeneratedKeyEvents = 4; 283 verify(mCarOccupantZoneService, times(numberOfGeneratedKeyEvents)).getDisplayIdForDriver( 284 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN)); 285 verify(mCaptureController, times(numberOfGeneratedKeyEvents)).onKeyEvent(anyInt(), 286 any(KeyEvent.class)); 287 verify(mDefaultKeyEventMainListener, never()) 288 .onKeyEvent(any(KeyEvent.class), anyInt(), anyInt()); 289 } 290 291 @Test testOnRotaryEvent_injectingRotaryNavigation_notConsumedByCaptureController()292 public void testOnRotaryEvent_injectingRotaryNavigation_notConsumedByCaptureController() { 293 RotaryEvent event = new RotaryEvent( 294 /* inputType= */ CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, 295 /* clockwise= */ true, 296 /* uptimeMillisForClicks= */ new long[]{1, 1}); 297 when(mCaptureController.onRotaryEvent( 298 same(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), same(event))).thenReturn(false); 299 300 mCarInputService.onRotaryEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN); 301 302 // Since mCaptureController processed RotaryEvent, then KeyEvent was generated or 303 // processed 304 int numberOfGeneratedKeyEvents = 4; 305 verify(mCarOccupantZoneService, times(numberOfGeneratedKeyEvents)).getDisplayIdForDriver( 306 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN)); 307 verify(mCaptureController, times(numberOfGeneratedKeyEvents)).onKeyEvent(anyInt(), 308 any(KeyEvent.class)); 309 verify(mDefaultKeyEventMainListener, times(numberOfGeneratedKeyEvents)).onKeyEvent( 310 any(KeyEvent.class), eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), anyInt()); 311 } 312 313 @Test testRequestInputEventCapture_delegatesToCaptureController()314 public void testRequestInputEventCapture_delegatesToCaptureController() { 315 ICarInputCallback callback = mock(ICarInputCallback.class); 316 int[] inputTypes = new int[]{CarInputManager.INPUT_TYPE_CUSTOM_INPUT_EVENT}; 317 int requestFlags = CarInputManager.CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT; 318 mCarInputService.requestInputEventCapture(callback, 319 CarOccupantZoneManager.DISPLAY_TYPE_MAIN, inputTypes, requestFlags); 320 321 verify(mCaptureController).requestInputEventCapture(same(callback), 322 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), same(inputTypes), eq(requestFlags)); 323 } 324 325 @Test testOnCustomInputEvent_delegatesToCaptureController()326 public void testOnCustomInputEvent_delegatesToCaptureController() { 327 CustomInputEvent event = new CustomInputEvent(INPUT_CODE_F1, 328 CarOccupantZoneManager.DISPLAY_TYPE_MAIN, /* repeatCounter= */ 1); 329 330 mCarInputService.onCustomInputEvent(event); 331 332 verify(mCaptureController).onCustomInputEvent(same(event)); 333 } 334 335 @Test testReleaseInputEventCapture_delegatesToCaptureController()336 public void testReleaseInputEventCapture_delegatesToCaptureController() { 337 ICarInputCallback callback = mock(ICarInputCallback.class); 338 mCarInputService.releaseInputEventCapture(callback, 339 CarOccupantZoneManager.DISPLAY_TYPE_MAIN); 340 341 verify(mCaptureController).releaseInputEventCapture(same(callback), 342 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN)); 343 } 344 345 @Test ordinaryEvents_onMainDisplay_routedToInputManager()346 public void ordinaryEvents_onMainDisplay_routedToInputManager() { 347 KeyEvent event = send(Key.DOWN, KeyEvent.KEYCODE_ENTER, Display.MAIN); 348 349 verify(mDefaultKeyEventMainListener).onKeyEvent(same(event), 350 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), anyInt()); 351 } 352 353 @Test ordinaryEvents_onInstrumentClusterDisplay_notRoutedToInputManager()354 public void ordinaryEvents_onInstrumentClusterDisplay_notRoutedToInputManager() { 355 send(Key.DOWN, KeyEvent.KEYCODE_ENTER, Display.INSTRUMENT_CLUSTER); 356 357 verify(mDefaultKeyEventMainListener, never()).onKeyEvent(any(), anyInt(), anyInt()); 358 } 359 360 @Test ordinaryEvents_onInstrumentClusterDisplay_routedToListener()361 public void ordinaryEvents_onInstrumentClusterDisplay_routedToListener() { 362 CarInputService.KeyEventListener listener = mock(CarInputService.KeyEventListener.class); 363 mCarInputService.setInstrumentClusterKeyListener(listener); 364 365 KeyEvent event = send(Key.DOWN, KeyEvent.KEYCODE_ENTER, Display.INSTRUMENT_CLUSTER); 366 verify(listener).onKeyEvent(event); 367 } 368 369 @Test registerKeyEventListener_separateListenersWithSameEventsOfInterest_fails()370 public void registerKeyEventListener_separateListenersWithSameEventsOfInterest_fails() { 371 CarInputService.KeyEventListener listener1 = mock(CarInputService.KeyEventListener.class); 372 CarInputService.KeyEventListener listener2 = mock(CarInputService.KeyEventListener.class); 373 List<Integer> interestedEvents = List.of(KeyEvent.KEYCODE_HOME, KeyEvent.KEYCODE_0); 374 mCarInputService.registerKeyEventListener(listener1, interestedEvents); 375 376 IllegalArgumentException thrown = Assert.assertThrows(IllegalArgumentException.class, 377 () -> mCarInputService.registerKeyEventListener(listener2, interestedEvents)); 378 379 assertWithMessage("Register key event listener exception") 380 .that(thrown).hasMessageThat() 381 .contains("Event " + KeyEvent.keyCodeToString(KeyEvent.KEYCODE_HOME) 382 + " already registered to another listener"); 383 } 384 385 @Test registerKeyEventListener_separateListenersWithOverlappingEventsOfInterest_fails()386 public void registerKeyEventListener_separateListenersWithOverlappingEventsOfInterest_fails() { 387 CarInputService.KeyEventListener listener1 = mock(CarInputService.KeyEventListener.class); 388 CarInputService.KeyEventListener listener2 = mock(CarInputService.KeyEventListener.class); 389 List<Integer> interestedEvents1 = List.of(KeyEvent.KEYCODE_HOME, KeyEvent.KEYCODE_0); 390 List<Integer> interestedEvents2 = List.of(KeyEvent.KEYCODE_1, KeyEvent.KEYCODE_HOME); 391 mCarInputService.registerKeyEventListener(listener1, interestedEvents1); 392 393 IllegalArgumentException thrown = Assert.assertThrows(IllegalArgumentException.class, 394 () -> mCarInputService.registerKeyEventListener(listener2, interestedEvents2)); 395 396 assertWithMessage("Register key event listener") 397 .that(thrown).hasMessageThat() 398 .contains("Event " + KeyEvent.keyCodeToString(KeyEvent.KEYCODE_HOME) 399 + " already registered to another listener"); 400 } 401 402 @Test registerKeyEventListener_withNullListener_fails()403 public void registerKeyEventListener_withNullListener_fails() { 404 var interestedEvents = List.of(KeyEvent.KEYCODE_HOME, KeyEvent.KEYCODE_0); 405 406 NullPointerException thrown = Assert.assertThrows(NullPointerException.class, 407 () -> mCarInputService.registerKeyEventListener(/* listener= */ null, 408 interestedEvents)); 409 410 assertWithMessage("Register null key event listener exception") 411 .that(thrown).hasMessageThat().contains("Key event listener"); 412 } 413 414 @Test registerKeyEventListener_withNullKeyEventList_fails()415 public void registerKeyEventListener_withNullKeyEventList_fails() { 416 CarInputService.KeyEventListener listener = mock(CarInputService.KeyEventListener.class); 417 418 NullPointerException thrown = Assert.assertThrows(NullPointerException.class, 419 () -> mCarInputService.registerKeyEventListener(listener, 420 /* keyCodesOfInterest= */ null)); 421 422 assertWithMessage("Register null key events of interest exception") 423 .that(thrown).hasMessageThat().contains("Key events of interest"); 424 } 425 426 @Test registerKeyEventListener_withEmptyKeyEventList_fails()427 public void registerKeyEventListener_withEmptyKeyEventList_fails() { 428 CarInputService.KeyEventListener listener = mock(CarInputService.KeyEventListener.class); 429 430 IllegalArgumentException thrown = Assert.assertThrows(IllegalArgumentException.class, 431 () -> mCarInputService.registerKeyEventListener(listener, 432 /* keyCodesOfInterest= */ Collections.emptyList())); 433 434 assertWithMessage("Register empty key events of interest exception") 435 .that(thrown).hasMessageThat().contains("Key events of interest"); 436 } 437 438 @Test unregisterKeyEventListener_withNullListener_fails()439 public void unregisterKeyEventListener_withNullListener_fails() { 440 NullPointerException thrown = Assert.assertThrows(NullPointerException.class, 441 () -> mCarInputService.unregisterKeyEventListener(/* listener= */ null)); 442 443 assertWithMessage("Unregister null key event listener exception") 444 .that(thrown).hasMessageThat().contains("Key event listener"); 445 } 446 447 @Test onKeyEvent_afterUnregistering_doesNotCallsListener()448 public void onKeyEvent_afterUnregistering_doesNotCallsListener() { 449 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HOME); 450 CarInputService.KeyEventListener listener = mock(CarInputService.KeyEventListener.class); 451 var interestedEvents = List.of(KeyEvent.KEYCODE_HOME, KeyEvent.KEYCODE_0); 452 mCarInputService.registerKeyEventListener(listener, interestedEvents); 453 mCarInputService.unregisterKeyEventListener(listener); 454 455 mCarInputService.onKeyEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 456 PASSENGER_SEAT); 457 458 verify(listener, never()).onKeyEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 459 PASSENGER_SEAT); 460 } 461 462 @Test onKeyEvent_withSingleListener_callsListener()463 public void onKeyEvent_withSingleListener_callsListener() { 464 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HOME); 465 CarInputService.KeyEventListener listener = mock(CarInputService.KeyEventListener.class); 466 List<Integer> interestedEvents = List.of(KeyEvent.KEYCODE_HOME, KeyEvent.KEYCODE_0); 467 mCarInputService.registerKeyEventListener(listener, interestedEvents); 468 469 mCarInputService.onKeyEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 470 PASSENGER_SEAT); 471 472 verify(listener).onKeyEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 473 PASSENGER_SEAT); 474 } 475 476 @Test onKeyEvent_withMultipleListeners_callToListener()477 public void onKeyEvent_withMultipleListeners_callToListener() { 478 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HOME); 479 CarInputService.KeyEventListener listener1 = mock(CarInputService.KeyEventListener.class); 480 CarInputService.KeyEventListener listener2 = mock(CarInputService.KeyEventListener.class); 481 List<Integer> interestedEvents1 = List.of(KeyEvent.KEYCODE_0); 482 List<Integer> interestedEvents2 = List.of(KeyEvent.KEYCODE_HOME); 483 mCarInputService.registerKeyEventListener(listener1, interestedEvents1); 484 mCarInputService.registerKeyEventListener(listener2, interestedEvents2); 485 486 mCarInputService.onKeyEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 487 PASSENGER_SEAT); 488 489 verify(listener1, never()).onKeyEvent(any(), anyInt(), anyInt()); 490 verify(listener2).onKeyEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 491 PASSENGER_SEAT); 492 } 493 494 @Test onKeyEvent_withMultipleListeners_noCallToListeners()495 public void onKeyEvent_withMultipleListeners_noCallToListeners() { 496 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_1); 497 CarInputService.KeyEventListener listener1 = mock(CarInputService.KeyEventListener.class); 498 CarInputService.KeyEventListener listener2 = mock(CarInputService.KeyEventListener.class); 499 List<Integer> interestedEvents1 = List.of(KeyEvent.KEYCODE_0); 500 List<Integer> interestedEvents2 = List.of(KeyEvent.KEYCODE_HOME); 501 mCarInputService.registerKeyEventListener(listener1, interestedEvents1); 502 mCarInputService.registerKeyEventListener(listener2, interestedEvents2); 503 504 mCarInputService.onKeyEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 505 PASSENGER_SEAT); 506 507 verify(listener1, never()).onKeyEvent(any(), anyInt(), anyInt()); 508 verify(listener2, never()).onKeyEvent(any(), anyInt(), anyInt()); 509 } 510 511 @Test customEventHandler_capturesDisplayMainEvent_capturedByInputController()512 public void customEventHandler_capturesDisplayMainEvent_capturedByInputController() { 513 CarInputService.KeyEventListener instrumentClusterListener = 514 setupInstrumentClusterListener(); 515 516 // Assume mCaptureController will consume every event. 517 when(mCaptureController.onKeyEvent(anyInt(), any(KeyEvent.class))).thenReturn(true); 518 519 KeyEvent event = send(Key.DOWN, KeyEvent.KEYCODE_ENTER, Display.MAIN); 520 verify(instrumentClusterListener, never()).onKeyEvent(any(KeyEvent.class)); 521 verify(mCaptureController).onKeyEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, event); 522 verify(mDefaultKeyEventMainListener, never()) 523 .onKeyEvent(any(KeyEvent.class), anyInt(), anyInt()); 524 } 525 526 @Test customEventHandler_capturesDisplayMainEvent_missedByInputController()527 public void customEventHandler_capturesDisplayMainEvent_missedByInputController() { 528 CarInputService.KeyEventListener instrumentClusterListener = 529 setupInstrumentClusterListener(); 530 531 // Assume mCaptureController will consume every event. 532 when(mCaptureController.onKeyEvent(anyInt(), any(KeyEvent.class))).thenReturn(false); 533 534 KeyEvent event = send(Key.DOWN, KeyEvent.KEYCODE_ENTER, Display.MAIN); 535 verify(instrumentClusterListener, never()).onKeyEvent(any(KeyEvent.class)); 536 verify(mCaptureController).onKeyEvent(anyInt(), any(KeyEvent.class)); 537 verify(mDefaultKeyEventMainListener).onKeyEvent(same(event), 538 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), anyInt()); 539 } 540 541 @Test customEventHandler_capturesClusterEvents_capturedByInstrumentCluster()542 public void customEventHandler_capturesClusterEvents_capturedByInstrumentCluster() { 543 CarInputService.KeyEventListener instrumentClusterListener = 544 setupInstrumentClusterListener(); 545 546 // Assume mCaptureController will consume every event. 547 when(mCaptureController.onKeyEvent(anyInt(), any(KeyEvent.class))).thenReturn(true); 548 549 KeyEvent event = send(Key.DOWN, KeyEvent.KEYCODE_ENTER, Display.INSTRUMENT_CLUSTER); 550 verify(instrumentClusterListener).onKeyEvent(event); 551 verify(mCaptureController, never()).onKeyEvent(anyInt(), any(KeyEvent.class)); 552 verify(mDefaultKeyEventMainListener, never()) 553 .onKeyEvent(any(KeyEvent.class), anyInt(), anyInt()); 554 } 555 setupInstrumentClusterListener()556 private CarInputService.KeyEventListener setupInstrumentClusterListener() { 557 CarInputService.KeyEventListener instrumentClusterListener = 558 mock(CarInputService.KeyEventListener.class); 559 mCarInputService.setInstrumentClusterKeyListener(instrumentClusterListener); 560 return instrumentClusterListener; 561 } 562 563 @Test voiceKey_shortPress_withRegisteredEventHandler_triggersEventHandler()564 public void voiceKey_shortPress_withRegisteredEventHandler_triggersEventHandler() { 565 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 566 registerProjectionKeyEventHandler( 567 CarProjectionManager.KEY_EVENT_VOICE_SEARCH_SHORT_PRESS_KEY_UP); 568 569 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 570 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 571 572 verify(eventHandler) 573 .onKeyEvent(CarProjectionManager.KEY_EVENT_VOICE_SEARCH_SHORT_PRESS_KEY_UP); 574 } 575 576 @Test voiceKey_longPress_withRegisteredEventHandler_triggersEventHandler()577 public void voiceKey_longPress_withRegisteredEventHandler_triggersEventHandler() { 578 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 579 registerProjectionKeyEventHandler( 580 CarProjectionManager.KEY_EVENT_VOICE_SEARCH_SHORT_PRESS_KEY_UP, 581 CarProjectionManager.KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_DOWN); 582 583 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 584 verify(eventHandler, never()).onKeyEvent(anyInt()); 585 586 // Simulate the long-press timer expiring. 587 flushHandler(); 588 verify(eventHandler) 589 .onKeyEvent(CarProjectionManager.KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_DOWN); 590 591 // Ensure that the short-press handler is *not* called. 592 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 593 flushHandler(); 594 verify(eventHandler, never()) 595 .onKeyEvent(CarProjectionManager.KEY_EVENT_VOICE_SEARCH_SHORT_PRESS_KEY_UP); 596 } 597 598 @Test voiceKey_shortPress_withoutRegisteredEventHandler_triggersAssistUtils()599 public void voiceKey_shortPress_withoutRegisteredEventHandler_triggersAssistUtils() { 600 doReturn(true).when( 601 () -> AssistUtilsHelper.showPushToTalkSessionForActiveService(eq(mContext), any())); 602 603 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 604 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 605 } 606 607 @Test voiceKey_longPress_withoutRegisteredEventHandler_triggersAssistUtils()608 public void voiceKey_longPress_withoutRegisteredEventHandler_triggersAssistUtils() { 609 doReturn(true).when( 610 () -> AssistUtilsHelper.showPushToTalkSessionForActiveService(eq(mContext), any())); 611 612 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 613 flushHandler(); 614 615 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 616 617 // NOTE: extend mockito doesn't provide verifyNoMoreInteractions(), so we'd need to 618 // explicitly call verify() and verify(never()). But since AssistUtilHelper only has one 619 // static method, we don't need the latter. 620 verify(() -> AssistUtilsHelper.showPushToTalkSessionForActiveService(eq(mContext), any())); 621 } 622 623 /** 624 * Testing long press triggers Bluetooth voice recognition. 625 * 626 * Based on current implementation of {@link CarInputService#handleVoiceAssistLongPress}, 627 * long press of the button should trigger Bluetooth voice recognition if: 628 * (a) {@link CarProjectionManager.ProjectionKeyEventHandler} did not subscribe for the 629 * event, or if the key event handler does not exit; and 630 * (b) Bluetooth voice recognition is enabled. 631 * 632 * Preconditions: 633 * - Bluetooth voice recognition is enabled. 634 * - No {@link CarProjectionManager.ProjectionKeyEventHandler} registered for the key event. 635 * Action: 636 * - Long press the voice assistant key. 637 * Results: 638 * - Bluetooth voice recognition is invoked. 639 */ 640 @Test voiceKey_longPress_bluetoothVoiceRecognitionIsEnabled_triggersBluetoothAssist()641 public void voiceKey_longPress_bluetoothVoiceRecognitionIsEnabled_triggersBluetoothAssist() { 642 mockEnableLongPressBluetoothVoiceRecognitionProperty(true); 643 644 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 645 flushHandler(); 646 647 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 648 649 verify(mCarBluetoothService, times(1)).startBluetoothVoiceRecognition(); 650 } 651 652 /** 653 * Testing long press triggers Bluetooth pairing flow. 654 * 655 * Based on current implementation of {@link CarInputService#handleVoiceAssistLongPress}, 656 * long press of the button should trigger Bluetooth pairing flow if: 657 * (a) {@link CarProjectionManager.ProjectionKeyEventHandler} did not subscribe for the 658 * event, or if the key event handler does not exit; and 659 * (b) Bluetooth voice recognition is disabled. 660 * (c) enableLongPressBluetoothPairing is enabled. 661 * (d) No Bluetooth devices are connected. 662 * 663 * Preconditions: 664 * - enableLongPressBluetoothPairing is enabled. 665 * - No {@link CarProjectionManager.ProjectionKeyEventHandler} registered for the key event. 666 * - Bluetooth voice recognition is disabled. 667 * - No Bluetooth devices are connected. 668 * Action: 669 * - Long press the voice assistant key. 670 * Results: 671 * - A intent with ACTION_BLUETOOTH_SETTINGS is sent. 672 */ 673 @Test 674 @RequiresFlagsEnabled(Flags.FLAG_CAR_INPUT_START_BTPAIRING_LPTT) voiceKey_longPress_bluetoothPairingIsEnabled_triggersBluetoothPairing()675 public void voiceKey_longPress_bluetoothPairingIsEnabled_triggersBluetoothPairing() { 676 677 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 678 679 mockEnableLongPressBluetoothVoiceRecognitionProperty(false); 680 mockEnableLongPressBluetoothPairingProperty(true); 681 682 when(mContext.getSystemService(BluetoothManager.class)).thenReturn(mMockBluetoothManager); 683 when(mMockBluetoothManager.getAdapter()).thenReturn(mMockBluetoothAdapter); 684 when(mMockBluetoothAdapter.getConnectionState()).thenReturn( 685 BluetoothAdapter.STATE_DISCONNECTED); 686 687 doNothing().when(mContext).startActivityAsUser(any(), any()); 688 689 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 690 flushHandler(); 691 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 692 693 verify(mContext).startActivityAsUser( 694 intentCaptor.capture(), eq(UserHandle.CURRENT)); 695 assertThat(intentCaptor.getValue().getAction()) 696 .isEqualTo(Settings.ACTION_BLUETOOTH_SETTINGS); 697 } 698 699 /** 700 * Testing long press not triggers pairing flow if there are Bluetooth device connected. 701 * 702 * Based on current implementation of {@link CarInputService#handleVoiceAssistLongPress}, 703 * long press of the button should not trigger Bluetooth pairing flow if: 704 * (a) {@link CarProjectionManager.ProjectionKeyEventHandler} did not subscribe for the 705 * event, or if the key event handler does not exit; and 706 * (b) Bluetooth voice recognition is disabled. 707 * (c) enableLongPressBluetoothPairing is enabled. 708 * (d) If there are Bluetooth device connected 709 * 710 * Preconditions: 711 * - enableLongPressBluetoothPairing is enabled. 712 * - No {@link CarProjectionManager.ProjectionKeyEventHandler} registered for the key event. 713 * - Bluetooth voice recognition is disabled. 714 * - Bluetooth devices are connected. 715 * Action: 716 * - Long press the voice assistant key. 717 * Results: 718 * - No intent sent. 719 */ 720 @Test 721 @RequiresFlagsEnabled(Flags.FLAG_CAR_INPUT_START_BTPAIRING_LPTT) voiceKey_longPress_bluetoothPairingIsEnabled_not_triggersBluetoothPairing()722 public void voiceKey_longPress_bluetoothPairingIsEnabled_not_triggersBluetoothPairing() { 723 724 mockEnableLongPressBluetoothVoiceRecognitionProperty(false); 725 mockEnableLongPressBluetoothPairingProperty(true); 726 727 when(mContext.getSystemService(BluetoothManager.class)).thenReturn(mMockBluetoothManager); 728 when(mMockBluetoothManager.getAdapter()).thenReturn(mMockBluetoothAdapter); 729 when(mMockBluetoothAdapter.getConnectionState()).thenReturn( 730 BluetoothAdapter.STATE_CONNECTED); 731 732 doNothing().when(mContext).startActivityAsUser(any(), any()); 733 734 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 735 flushHandler(); 736 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 737 738 verify(mContext, never()).startActivityAsUser(any(), any()); 739 } 740 741 742 /** 743 * Testing short press does not trigger Bluetooth voice recognition. 744 * 745 * Based on current implementation of {@link CarInputService#handleVoiceAssistKey}, 746 * short press of the button should not trigger Bluetooth, and instead launch the default 747 * voice assistant handler. 748 * 749 * Preconditions: 750 * - Bluetooth voice recognition is enabled. 751 * Action: 752 * - Short press the voice assistant key. 753 * Results: 754 * - Bluetooth voice recognition is not invoked. 755 * - Default assistant handler is invoked instead. 756 */ 757 @Test voiceKey_shortPress_bluetoothVoiceRecognitionIsEnabled_triggersAssistUtils()758 public void voiceKey_shortPress_bluetoothVoiceRecognitionIsEnabled_triggersAssistUtils() { 759 mockEnableLongPressBluetoothVoiceRecognitionProperty(true); 760 761 doReturn(true).when( 762 () -> AssistUtilsHelper.showPushToTalkSessionForActiveService(eq(mContext), any())); 763 764 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 765 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 766 767 verify(mCarBluetoothService, never()).startBluetoothVoiceRecognition(); 768 verify(() -> AssistUtilsHelper.showPushToTalkSessionForActiveService(eq(mContext), any())); 769 } 770 771 @Test voiceKey_keyDown_withEventHandler_triggersEventHandler()772 public void voiceKey_keyDown_withEventHandler_triggersEventHandler() { 773 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 774 registerProjectionKeyEventHandler( 775 CarProjectionManager.KEY_EVENT_VOICE_SEARCH_KEY_DOWN); 776 777 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 778 779 verify(eventHandler).onKeyEvent(CarProjectionManager.KEY_EVENT_VOICE_SEARCH_KEY_DOWN); 780 } 781 782 @Test voiceKey_keyUp_afterLongPress_withEventHandler_triggersEventHandler()783 public void voiceKey_keyUp_afterLongPress_withEventHandler_triggersEventHandler() { 784 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 785 registerProjectionKeyEventHandler( 786 CarProjectionManager.KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_UP); 787 788 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 789 flushHandler(); 790 verify(eventHandler, never()) 791 .onKeyEvent(CarProjectionManager.KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_UP); 792 793 send(Key.UP, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 794 verify(eventHandler) 795 .onKeyEvent(CarProjectionManager.KEY_EVENT_VOICE_SEARCH_LONG_PRESS_KEY_UP); 796 } 797 798 @Test voiceKey_repeatedEvents_ignored()799 public void voiceKey_repeatedEvents_ignored() { 800 // Pressing a key starts the long-press timer. 801 send(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN); 802 verify(mHandler).sendMessageAtTime(any(), anyLong()); 803 clearInvocations(mHandler); 804 805 // Repeated KEY_DOWN events don't reset the timer. 806 sendWithRepeat(Key.DOWN, KeyEvent.KEYCODE_VOICE_ASSIST, Display.MAIN, 1); 807 verify(mHandler, never()).sendMessageAtTime(any(), anyLong()); 808 } 809 810 @Test callKey_shortPress_withoutEventHandler_launchesDialer()811 public void callKey_shortPress_withoutEventHandler_launchesDialer() { 812 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 813 814 doNothing().when(mContext).startActivityAsUser(any(), any()); 815 816 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 817 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 818 819 verify(mContext).startActivityAsUser( 820 intentCaptor.capture(), eq(UserHandle.CURRENT)); 821 assertThat(intentCaptor.getValue().getAction()).isEqualTo(Intent.ACTION_DIAL); 822 } 823 824 @Test callKey_shortPress_withoutEventHandler_whenCallRinging_answersCall()825 public void callKey_shortPress_withoutEventHandler_whenCallRinging_answersCall() { 826 when(mTelecomManager.isRinging()).thenReturn(true); 827 828 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 829 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 830 831 verify(mTelecomManager).acceptRingingCall(); 832 // Ensure default handler does not run. 833 verify(mContext, never()).startActivityAsUser(any(), any()); 834 } 835 836 @Test callKey_shortPress_withEventHandler_triggersEventHandler()837 public void callKey_shortPress_withEventHandler_triggersEventHandler() { 838 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 839 registerProjectionKeyEventHandler( 840 CarProjectionManager.KEY_EVENT_CALL_SHORT_PRESS_KEY_UP); 841 842 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 843 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 844 845 verify(eventHandler).onKeyEvent(CarProjectionManager.KEY_EVENT_CALL_SHORT_PRESS_KEY_UP); 846 // Ensure default handlers do not run. 847 verify(mTelecomManager, never()).acceptRingingCall(); 848 verify(mContext, never()).startActivityAsUser(any(), any()); 849 } 850 851 @Test callKey_shortPress_withEventHandler_whenCallRinging_answersCall()852 public void callKey_shortPress_withEventHandler_whenCallRinging_answersCall() { 853 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 854 registerProjectionKeyEventHandler( 855 CarProjectionManager.KEY_EVENT_CALL_SHORT_PRESS_KEY_UP); 856 when(mTelecomManager.isRinging()).thenReturn(true); 857 858 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 859 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 860 861 verify(mTelecomManager).acceptRingingCall(); 862 verify(eventHandler, never()).onKeyEvent(anyInt()); 863 } 864 865 @Test callKey_shortPress_duringCall_endCallViaCallButtonOn_endsCall()866 public void callKey_shortPress_duringCall_endCallViaCallButtonOn_endsCall() { 867 when(mShouldCallButtonEndOngoingCallSupplier.getAsBoolean()).thenReturn(true); 868 when(mTelecomManager.isInCall()).thenReturn(true); 869 870 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 871 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 872 873 verify(mTelecomManager).endCall(); 874 } 875 876 @Test callKey_shortPress_duringCall_endCallViaCallButtonOff_doesNotEndCall()877 public void callKey_shortPress_duringCall_endCallViaCallButtonOff_doesNotEndCall() { 878 when(mTelecomManager.isInCall()).thenReturn(true); 879 880 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 881 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 882 883 verify(mTelecomManager, never()).endCall(); 884 } 885 886 @Test callKey_longPress_withoutEventHandler_redialsLastCall()887 public void callKey_longPress_withoutEventHandler_redialsLastCall() { 888 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 889 890 when(mLastCallSupplier.get()).thenReturn("1234567890"); 891 doNothing().when(mContext).startActivityAsUser(any(), any()); 892 893 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 894 flushHandler(); 895 896 verify(mContext).startActivityAsUser( 897 intentCaptor.capture(), eq(UserHandle.CURRENT)); 898 899 Intent intent = intentCaptor.getValue(); 900 assertThat(intent.getAction()).isEqualTo(Intent.ACTION_CALL); 901 assertThat(intent.getData()).isEqualTo(Uri.parse("tel:1234567890")); 902 903 clearInvocations(mContext); 904 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 905 verify(mContext, never()).startActivityAsUser(any(), any()); 906 } 907 908 @Test callKey_longPress_withoutEventHandler_withNoLastCall_doesNothing()909 public void callKey_longPress_withoutEventHandler_withNoLastCall_doesNothing() { 910 when(mLastCallSupplier.get()).thenReturn(""); 911 912 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 913 flushHandler(); 914 915 verify(mContext, never()).startActivityAsUser(any(), any()); 916 } 917 918 @Test callKey_longPress_withoutEventHandler_whenCallRinging_answersCall()919 public void callKey_longPress_withoutEventHandler_whenCallRinging_answersCall() { 920 when(mTelecomManager.isRinging()).thenReturn(true); 921 922 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 923 flushHandler(); 924 925 verify(mTelecomManager).acceptRingingCall(); 926 927 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 928 // Ensure that default handler does not run, either after accepting ringing call, 929 // or as a result of key-up. 930 verify(mContext, never()).startActivityAsUser(any(), any()); 931 } 932 933 @Test callKey_longPress_withEventHandler_triggersEventHandler()934 public void callKey_longPress_withEventHandler_triggersEventHandler() { 935 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 936 registerProjectionKeyEventHandler( 937 CarProjectionManager.KEY_EVENT_CALL_LONG_PRESS_KEY_DOWN); 938 939 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 940 flushHandler(); 941 942 verify(eventHandler).onKeyEvent(CarProjectionManager.KEY_EVENT_CALL_LONG_PRESS_KEY_DOWN); 943 verify(mContext, never()).startActivityAsUser(any(), any()); 944 } 945 946 @Test callKey_longPress_withEventHandler_whenCallRinging_answersCall()947 public void callKey_longPress_withEventHandler_whenCallRinging_answersCall() { 948 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 949 registerProjectionKeyEventHandler( 950 CarProjectionManager.KEY_EVENT_CALL_LONG_PRESS_KEY_DOWN); 951 when(mTelecomManager.isRinging()).thenReturn(true); 952 953 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 954 flushHandler(); 955 956 verify(mTelecomManager).acceptRingingCall(); 957 958 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 959 // Ensure that event handler does not run, either after accepting ringing call, 960 // or as a result of key-up. 961 verify(eventHandler, never()).onKeyEvent(anyInt()); 962 } 963 964 @Test callKey_longPress_duringCall_endCallViaCallButtonOn_endsCall()965 public void callKey_longPress_duringCall_endCallViaCallButtonOn_endsCall() { 966 when(mShouldCallButtonEndOngoingCallSupplier.getAsBoolean()).thenReturn(true); 967 when(mTelecomManager.isInCall()).thenReturn(true); 968 969 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 970 flushHandler(); 971 972 verify(mTelecomManager).endCall(); 973 } 974 975 @Test callKey_longPress_duringCall_endCallViaCallButtonOff_doesNotEndCall()976 public void callKey_longPress_duringCall_endCallViaCallButtonOff_doesNotEndCall() { 977 when(mTelecomManager.isInCall()).thenReturn(true); 978 979 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 980 flushHandler(); 981 982 verify(mTelecomManager, never()).endCall(); 983 } 984 985 @Test callKey_keyDown_withEventHandler_triggersEventHandler()986 public void callKey_keyDown_withEventHandler_triggersEventHandler() { 987 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 988 registerProjectionKeyEventHandler( 989 CarProjectionManager.KEY_EVENT_CALL_KEY_DOWN); 990 991 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 992 993 verify(eventHandler).onKeyEvent(CarProjectionManager.KEY_EVENT_CALL_KEY_DOWN); 994 } 995 996 @Test callKey_keyUp_afterLongPress_withEventHandler_triggersEventHandler()997 public void callKey_keyUp_afterLongPress_withEventHandler_triggersEventHandler() { 998 CarProjectionManager.ProjectionKeyEventHandler eventHandler = 999 registerProjectionKeyEventHandler( 1000 CarProjectionManager.KEY_EVENT_CALL_LONG_PRESS_KEY_UP); 1001 1002 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 1003 flushHandler(); 1004 verify(eventHandler, never()) 1005 .onKeyEvent(CarProjectionManager.KEY_EVENT_CALL_LONG_PRESS_KEY_UP); 1006 1007 send(Key.UP, KeyEvent.KEYCODE_CALL, Display.MAIN); 1008 verify(eventHandler).onKeyEvent(CarProjectionManager.KEY_EVENT_CALL_LONG_PRESS_KEY_UP); 1009 } 1010 1011 @Test callKey_repeatedEvents_ignored()1012 public void callKey_repeatedEvents_ignored() { 1013 // Pressing a key starts the long-press timer. 1014 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 1015 verify(mHandler).sendMessageAtTime(any(), anyLong()); 1016 clearInvocations(mHandler); 1017 1018 // Repeated KEY_DOWN events don't reset the timer. 1019 sendWithRepeat(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN, 1); 1020 verify(mHandler, never()).sendMessageAtTime(any(), anyLong()); 1021 } 1022 1023 @Test longPressDelay_obeysValueFromSystem()1024 public void longPressDelay_obeysValueFromSystem() { 1025 final int systemDelay = 4242; 1026 1027 when(mLongPressDelaySupplier.getAsInt()).thenReturn(systemDelay); 1028 ArgumentCaptor<Long> timeCaptor = ArgumentCaptor.forClass(long.class); 1029 1030 long then = SystemClock.uptimeMillis(); 1031 send(Key.DOWN, KeyEvent.KEYCODE_CALL, Display.MAIN); 1032 long now = SystemClock.uptimeMillis(); 1033 1034 verify(mHandler).sendMessageAtTime(any(), timeCaptor.capture()); 1035 1036 // The message time must be the expected delay time (as provided by the supplier) after 1037 // the time the message was sent to the handler. We don't know that exact time, but we 1038 // can put a bound on it - it's no sooner than immediately before the call to send(), and no 1039 // later than immediately afterwards. Check to make sure the actual observed message time is 1040 // somewhere in the valid range. 1041 1042 assertThat(timeCaptor.getValue()).isIn(Range.closed(then + systemDelay, now + systemDelay)); 1043 } 1044 1045 @Test injectKeyEvent_throwsSecurityExceptionWithoutInjectEventsPermission()1046 public void injectKeyEvent_throwsSecurityExceptionWithoutInjectEventsPermission() { 1047 // Arrange 1048 doReturn(PackageManager.PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission( 1049 android.Manifest.permission.INJECT_EVENTS); 1050 1051 long currentTime = SystemClock.uptimeMillis(); 1052 KeyEvent event = new KeyEvent(/* downTime= */ currentTime, 1053 /* eventTime= */ currentTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 1054 /* repeat= */ 0); 1055 1056 // Act and assert 1057 Assert.assertThrows(SecurityException.class, 1058 () -> mCarInputService.injectKeyEvent(event, 1059 CarOccupantZoneManager.DISPLAY_TYPE_MAIN)); 1060 } 1061 1062 @Test injectKeyEvent_delegatesToOnKeyEvent()1063 public void injectKeyEvent_delegatesToOnKeyEvent() { 1064 long currentTime = SystemClock.uptimeMillis(); 1065 KeyEvent event = new KeyEvent(/* downTime= */ currentTime, 1066 /* eventTime= */ currentTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 1067 /* repeat= */ 0); 1068 event.setDisplayId(INVALID_DISPLAY); 1069 1070 injectKeyEventAndVerify(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN); 1071 1072 verify(mDefaultKeyEventMainListener).onKeyEvent(same(event), 1073 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), anyInt()); 1074 verify(mInstrumentClusterKeyListener, never()).onKeyEvent(same(event)); 1075 } 1076 1077 @Test injectKeyEvent_sendingKeyEventWithDefaultDisplayAgainstClusterDisplayType()1078 public void injectKeyEvent_sendingKeyEventWithDefaultDisplayAgainstClusterDisplayType() { 1079 long currentTime = SystemClock.uptimeMillis(); 1080 KeyEvent event = new KeyEvent(/* downTime= */ currentTime, 1081 /* eventTime= */ currentTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 1082 /* repeat= */ 0); 1083 event.setDisplayId(INVALID_DISPLAY); 1084 1085 injectKeyEventAndVerify(event, CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER); 1086 1087 verify(mDefaultKeyEventMainListener, never()).onKeyEvent(same(event), anyInt(), anyInt()); 1088 verify(mInstrumentClusterKeyListener).onKeyEvent(same(event)); 1089 } 1090 injectKeyEventAndVerify(KeyEvent event, @DisplayTypeEnum int displayType)1091 private void injectKeyEventAndVerify(KeyEvent event, @DisplayTypeEnum int displayType) { 1092 doReturn(PackageManager.PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission( 1093 android.Manifest.permission.INJECT_EVENTS); 1094 int someDisplayId = Integer.MAX_VALUE; 1095 when(mCarOccupantZoneService.getDisplayIdForDriver(anyInt())).thenReturn(someDisplayId); 1096 assertThat(event.getDisplayId()).isNotEqualTo(someDisplayId); 1097 1098 mCarInputService.injectKeyEvent(event, displayType); 1099 1100 verify(mCarOccupantZoneService).getDisplayIdForDriver(displayType); 1101 assertWithMessage("Event's display id not updated as expected").that( 1102 event.getDisplayId()).isEqualTo(someDisplayId); 1103 } 1104 1105 @Test onKey_assignDisplayId_mainDisplay()1106 public void onKey_assignDisplayId_mainDisplay() { 1107 // Act 1108 KeyEvent event = send(Key.DOWN, KeyEvent.KEYCODE_HOME, Display.MAIN); 1109 1110 // Arrange 1111 assertWithMessage("display id expected to be assigned with Display.DEFAULT_DISPLAY").that( 1112 event.getDisplayId()).isEqualTo(DEFAULT_DISPLAY); 1113 } 1114 1115 @Test onKey_assignDisplayId_clusterDisplay()1116 public void onKey_assignDisplayId_clusterDisplay() { 1117 // Act 1118 KeyEvent event = send(Key.DOWN, KeyEvent.KEYCODE_HOME, Display.INSTRUMENT_CLUSTER); 1119 1120 // Arrange 1121 assertWithMessage("display id expected to be assigned with Display.DEFAULT_DISPLAY").that( 1122 event.getDisplayId()).isEqualTo(DEFAULT_DISPLAY); 1123 } 1124 1125 @Test onKeyEvent_unknownSeat_throwsException()1126 public void onKeyEvent_unknownSeat_throwsException() { 1127 long currentTime = SystemClock.uptimeMillis(); 1128 KeyEvent event = new KeyEvent(/* downTime= */ currentTime, 1129 /* eventTime= */ currentTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A, 1130 /* repeat= */ 0); 1131 1132 IllegalArgumentException thrown = Assert.assertThrows(IllegalArgumentException.class, 1133 () -> mCarInputService.onKeyEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 1134 UNKNOWN_SEAT)); 1135 1136 assertWithMessage("Sent key event with unknown seat exception") 1137 .that(thrown).hasMessageThat() 1138 .contains("Unknown seat"); 1139 } 1140 1141 @Test onKeyEvent_keyCodeAtoDriverSeat_triggersDefaultKeyEventMainListener()1142 public void onKeyEvent_keyCodeAtoDriverSeat_triggersDefaultKeyEventMainListener() { 1143 when(mCaptureController.onKeyEvent(anyInt(), any(KeyEvent.class))).thenReturn(false); 1144 1145 KeyEvent event = send(Key.DOWN, KeyEvent.KEYCODE_A, Display.MAIN, DRIVER_SEAT); 1146 1147 verify(mCarPowerManagementService).notifyUserActivity(eq(DRIVER_DISPLAY_ID), anyLong()); 1148 verify(mDefaultKeyEventMainListener).onKeyEvent(same(event), 1149 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), eq(DRIVER_SEAT)); 1150 } 1151 1152 @Test onKeyEvent_keyCodeAtoPassengerSeat_triggersDefaultKeyEventMainListener()1153 public void onKeyEvent_keyCodeAtoPassengerSeat_triggersDefaultKeyEventMainListener() { 1154 when(mCaptureController.onKeyEvent(anyInt(), any(KeyEvent.class))).thenReturn(false); 1155 1156 KeyEvent event = send(Key.DOWN, KeyEvent.KEYCODE_A, Display.MAIN, PASSENGER_SEAT); 1157 1158 verify(mCarPowerManagementService).notifyUserActivity(eq(PASSENGER_DISPLAY_ID), anyLong()); 1159 verify(mDefaultKeyEventMainListener).onKeyEvent(same(event), 1160 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), eq(PASSENGER_SEAT)); 1161 } 1162 1163 @Test onKeyEvent_homeKeyUpToDriverSeat_triggersDefaultKeyEventMainListener()1164 public void onKeyEvent_homeKeyUpToDriverSeat_triggersDefaultKeyEventMainListener() { 1165 when(mCaptureController.onKeyEvent(anyInt(), any(KeyEvent.class))).thenReturn(false); 1166 1167 KeyEvent event = send(Key.UP, KeyEvent.KEYCODE_HOME, Display.MAIN, DRIVER_SEAT); 1168 1169 verify(mDefaultKeyEventMainListener).onKeyEvent(same(event), 1170 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), eq(DRIVER_SEAT)); 1171 verify(() -> CarServiceUtils.startHomeForUserAndDisplay(any(), anyInt(), anyInt()), 1172 never()); 1173 } 1174 1175 @Test onKeyEvent_homeKeyUpToInvalidSeat_doesNothing()1176 public void onKeyEvent_homeKeyUpToInvalidSeat_doesNothing() { 1177 int invalidSeat = -1; 1178 when(mCarOccupantZoneService.getOccupantZoneIdForSeat(eq(invalidSeat))) 1179 .thenReturn(OccupantZoneInfo.INVALID_ZONE_ID); 1180 1181 send(Key.UP, KeyEvent.KEYCODE_HOME, Display.MAIN, invalidSeat); 1182 1183 verify(() -> CarServiceUtils.startHomeForUserAndDisplay(any(), anyInt(), anyInt()), 1184 never()); 1185 } 1186 1187 @Test onKeyEvent_homeKeyDownToPassengerSeat_doesNothing()1188 public void onKeyEvent_homeKeyDownToPassengerSeat_doesNothing() { 1189 send(Key.DOWN, KeyEvent.KEYCODE_HOME, Display.MAIN, PASSENGER_SEAT); 1190 1191 verify(() -> CarServiceUtils.startHomeForUserAndDisplay(any(), anyInt(), anyInt()), 1192 never()); 1193 } 1194 1195 @Test onKeyEvent_homeKeyUpToPassengerSeat_triggersStartyHome()1196 public void onKeyEvent_homeKeyUpToPassengerSeat_triggersStartyHome() { 1197 doAnswer((invocation) -> null).when(() -> CarServiceUtils.startHomeForUserAndDisplay( 1198 any(Context.class), anyInt(), anyInt())); 1199 1200 send(Key.UP, KeyEvent.KEYCODE_HOME, Display.MAIN, PASSENGER_SEAT); 1201 1202 verify(() -> CarServiceUtils.startHomeForUserAndDisplay(mContext, PASSENGER_USER_ID, 1203 PASSENGER_DISPLAY_ID)); 1204 } 1205 1206 @Test onKeyEvent_powerKeyUpToDriverSeat_triggersDefaultKeyEventMainListener()1207 public void onKeyEvent_powerKeyUpToDriverSeat_triggersDefaultKeyEventMainListener() { 1208 when(mCaptureController.onKeyEvent(anyInt(), any(KeyEvent.class))).thenReturn(false); 1209 1210 KeyEvent event = send(Key.UP, KeyEvent.KEYCODE_POWER, Display.MAIN, DRIVER_SEAT); 1211 1212 verify(mDefaultKeyEventMainListener).onKeyEvent(same(event), 1213 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), eq(DRIVER_SEAT)); 1214 verify(mCarPowerManagementService, never()).setDisplayPowerState(anyInt(), anyBoolean()); 1215 } 1216 1217 @Test onKeyEvent_powerKeyDownToPassengerSeatWhenDisplayOn_doesNothing()1218 public void onKeyEvent_powerKeyDownToPassengerSeatWhenDisplayOn_doesNothing() { 1219 injectPowerKeyEventToSeat(Key.DOWN, /* isOn= */ true, PASSENGER_DISPLAY_ID, PASSENGER_SEAT); 1220 1221 verify(mCarPowerManagementService, never()).setDisplayPowerState(anyInt(), anyBoolean()); 1222 } 1223 1224 @Test onKeyEvent_powerKeyDownToPassengerSeatWhenDisplayOff_setsDisplayPowerOn()1225 public void onKeyEvent_powerKeyDownToPassengerSeatWhenDisplayOff_setsDisplayPowerOn() { 1226 injectPowerKeyEventToSeat(Key.DOWN, /* isOn= */ false, PASSENGER_DISPLAY_ID, 1227 PASSENGER_SEAT); 1228 1229 boolean expectedDisplaySetStatus = true; 1230 verify(mCarPowerManagementService).setDisplayPowerState(eq(PASSENGER_DISPLAY_ID), 1231 eq(expectedDisplaySetStatus)); 1232 } 1233 1234 @Test onKeyEvent_powerKeyUpToPassengerSeatWhenDisplayOn_setsDisplayPowerOff()1235 public void onKeyEvent_powerKeyUpToPassengerSeatWhenDisplayOn_setsDisplayPowerOff() { 1236 injectPowerKeyEventToSeat(Key.UP, /* isOn= */ true, PASSENGER_DISPLAY_ID, PASSENGER_SEAT); 1237 1238 boolean expectedDisplaySetStatus = false; 1239 verify(mCarPowerManagementService).setDisplayPowerState(eq(PASSENGER_DISPLAY_ID), 1240 eq(expectedDisplaySetStatus)); 1241 } 1242 1243 @Test onKeyEvent_powerKeyUpToPassengerSeatWhenDisplayOff_doesNothing()1244 public void onKeyEvent_powerKeyUpToPassengerSeatWhenDisplayOff_doesNothing() { 1245 injectPowerKeyEventToSeat(Key.UP, /* isOn= */ false, PASSENGER_DISPLAY_ID, PASSENGER_SEAT); 1246 1247 verify(mCarPowerManagementService, never()).setDisplayPowerState(anyInt(), anyBoolean()); 1248 } 1249 1250 @Test onKeyEvent_powerKeyDownToPassengerSeatWhenInvalidDisplayId_doesNothing()1251 public void onKeyEvent_powerKeyDownToPassengerSeatWhenInvalidDisplayId_doesNothing() { 1252 when(mCarOccupantZoneService.getDisplayForOccupant(eq(PASSENGER_ZONE_ID), 1253 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN))) 1254 .thenReturn(INVALID_DISPLAY); 1255 1256 send(Key.DOWN, KeyEvent.KEYCODE_POWER, Display.MAIN, PASSENGER_SEAT); 1257 1258 verify(mCarPowerManagementService, never()).setDisplayPowerState(anyInt(), anyBoolean()); 1259 } 1260 injectPowerKeyEventToSeat(Key action, boolean isOn, int displayId, int seat)1261 private KeyEvent injectPowerKeyEventToSeat(Key action, boolean isOn, int displayId, int seat) { 1262 when(mSystemInterface.isDisplayEnabled(eq(displayId))).thenReturn(isOn); 1263 1264 return send(action, KeyEvent.KEYCODE_POWER, Display.MAIN, seat); 1265 } 1266 1267 @Test onMotionEvent_injectsMotionEventToDriverSeat()1268 public void onMotionEvent_injectsMotionEventToDriverSeat() { 1269 long currentTime = SystemClock.uptimeMillis(); 1270 MotionEvent event = MotionEvent.obtain( 1271 /* downTime= */ currentTime, 1272 /* eventTime= */ currentTime, 1273 MotionEvent.ACTION_DOWN, 1274 /* X coordinate= */ 0.0f, 1275 /* Y coordinate= */ 0.0f, 1276 /* metaState= */ 0); 1277 1278 mCarInputService.onMotionEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 1279 DRIVER_SEAT); 1280 1281 verify(mDefaultMotionEventMainListener).onMotionEvent(same(event)); 1282 verify(mCarPowerManagementService).notifyUserActivity(eq(DRIVER_DISPLAY_ID), 1283 eq(currentTime)); 1284 } 1285 1286 @Test onMotionEvent_injectsMotionEventToPassengerSeat()1287 public void onMotionEvent_injectsMotionEventToPassengerSeat() { 1288 long currentTime = SystemClock.uptimeMillis(); 1289 MotionEvent event = MotionEvent.obtain( 1290 /* downTime= */ currentTime, 1291 /* eventTime= */ currentTime, 1292 MotionEvent.ACTION_DOWN, 1293 /* X coordinate= */ 0.0f, 1294 /* Y coordinate= */ 0.0f, 1295 /* metaState= */ 0); 1296 1297 mCarInputService.onMotionEvent(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 1298 PASSENGER_SEAT); 1299 1300 verify(mDefaultMotionEventMainListener).onMotionEvent(same(event)); 1301 verify(mCarPowerManagementService).notifyUserActivity(eq(PASSENGER_DISPLAY_ID), 1302 eq(currentTime)); 1303 } 1304 1305 @Test onMotionEvent_unknownSeat_throwsException()1306 public void onMotionEvent_unknownSeat_throwsException() { 1307 long currentTime = SystemClock.uptimeMillis(); 1308 MotionEvent event = MotionEvent.obtain( 1309 /* downTime= */ currentTime, 1310 /* eventTime= */ currentTime, 1311 MotionEvent.ACTION_DOWN, 1312 /* X coordinate= */ 0.0f, 1313 /* Y coordinate= */ 0.0f, 1314 /* metaState= */ 0); 1315 1316 IllegalArgumentException thrown = Assert.assertThrows(IllegalArgumentException.class, 1317 () -> mCarInputService.onMotionEvent(event, 1318 CarOccupantZoneManager.DISPLAY_TYPE_MAIN, UNKNOWN_SEAT)); 1319 1320 assertWithMessage("Sent motion event with unknown seat exception") 1321 .that(thrown).hasMessageThat() 1322 .contains("Unknown seat"); 1323 } 1324 1325 @Test injectKeyEventForDriver_delegatesToOnKeyEvent()1326 public void injectKeyEventForDriver_delegatesToOnKeyEvent() { 1327 doReturn(PackageManager.PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission( 1328 android.Manifest.permission.INJECT_EVENTS); 1329 when(mCaptureController.onKeyEvent(anyInt(), any(KeyEvent.class))).thenReturn(false); 1330 long currentTime = SystemClock.uptimeMillis(); 1331 KeyEvent event = new KeyEvent( 1332 /* downTime= */ currentTime, 1333 /* eventTime= */ currentTime, 1334 KeyEvent.ACTION_DOWN, 1335 KeyEvent.KEYCODE_ENTER, 1336 /* repeat= */ 0); 1337 1338 mCarInputService.injectKeyEventForSeat(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 1339 DRIVER_SEAT); 1340 1341 verify(mDefaultKeyEventMainListener).onKeyEvent(same(event), 1342 eq(CarOccupantZoneManager.DISPLAY_TYPE_MAIN), eq(DRIVER_SEAT)); 1343 } 1344 1345 @Test injectKeyEventForDriver_throwsSecurityExceptionWithoutInjectEventsPermission()1346 public void injectKeyEventForDriver_throwsSecurityExceptionWithoutInjectEventsPermission() { 1347 doReturn(PackageManager.PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission( 1348 android.Manifest.permission.INJECT_EVENTS); 1349 long currentTime = SystemClock.uptimeMillis(); 1350 KeyEvent event = new KeyEvent( 1351 /* downTime= */ currentTime, 1352 /* eventTime= */ currentTime, 1353 KeyEvent.ACTION_DOWN, 1354 KeyEvent.KEYCODE_ENTER, 1355 /* repeat= */ 0); 1356 1357 // Act and assert 1358 Assert.assertThrows(SecurityException.class, 1359 () -> mCarInputService.injectKeyEventForSeat(event, 1360 CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 1361 DRIVER_SEAT)); 1362 } 1363 1364 @Test injectMotionEventForDriver_delegatesToOnKeyEvent()1365 public void injectMotionEventForDriver_delegatesToOnKeyEvent() { 1366 doReturn(PackageManager.PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission( 1367 android.Manifest.permission.INJECT_EVENTS); 1368 when(mCaptureController.onKeyEvent(anyInt(), any(KeyEvent.class))).thenReturn(false); 1369 long currentTime = SystemClock.uptimeMillis(); 1370 MotionEvent event = MotionEvent.obtain( 1371 /* downTime= */ currentTime, 1372 /* eventTime= */ currentTime, 1373 MotionEvent.ACTION_DOWN, 1374 /* X coordinate= */ 0.0f, 1375 /* Y coordinate= */ 0.0f, 1376 /* metaState= */ 0); 1377 1378 mCarInputService.injectMotionEventForSeat(event, CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 1379 DRIVER_SEAT); 1380 1381 verify(mDefaultMotionEventMainListener).onMotionEvent(event); 1382 } 1383 1384 @Test injectMotionEventForDriver_throwsSecurityExceptionWithoutInjectEventsPermission()1385 public void injectMotionEventForDriver_throwsSecurityExceptionWithoutInjectEventsPermission() { 1386 doReturn(PackageManager.PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission( 1387 android.Manifest.permission.INJECT_EVENTS); 1388 1389 long currentTime = SystemClock.uptimeMillis(); 1390 MotionEvent event = MotionEvent.obtain( 1391 /* downTime= */ currentTime, 1392 /* eventTime= */ currentTime, 1393 MotionEvent.ACTION_DOWN, 1394 /* X coordinate= */ 0.0f, 1395 /* Y coordinate= */ 0.0f, 1396 /* metaState= */ 0); 1397 1398 Assert.assertThrows(SecurityException.class, 1399 () -> mCarInputService.injectMotionEventForSeat(event, 1400 CarOccupantZoneManager.DISPLAY_TYPE_MAIN, 1401 DRIVER_SEAT)); 1402 } 1403 1404 private enum Key {DOWN, UP} 1405 1406 private enum Display {MAIN, INSTRUMENT_CLUSTER} 1407 send(Key action, int keyCode, Display display)1408 private KeyEvent send(Key action, int keyCode, Display display) { 1409 return sendWithRepeat(action, keyCode, display, 0); 1410 } 1411 sendWithRepeat(Key action, int keyCode, Display display, int repeatCount)1412 private KeyEvent sendWithRepeat(Key action, int keyCode, Display display, int repeatCount) { 1413 KeyEvent event = new KeyEvent( 1414 /* downTime= */ 0L, 1415 /* eventTime= */ 0L, 1416 action == Key.DOWN ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP, 1417 keyCode, 1418 repeatCount); 1419 event.setDisplayId(INVALID_DISPLAY); 1420 mCarInputService.onKeyEvent( 1421 event, 1422 display == Display.MAIN 1423 ? CarOccupantZoneManager.DISPLAY_TYPE_MAIN 1424 : CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER); 1425 return event; 1426 } 1427 send(Key action, int keyCode, Display display, int seat)1428 private KeyEvent send(Key action, int keyCode, Display display, int seat) { 1429 return sendWithRepeatAndSeat(action, keyCode, display, 0, seat); 1430 } 1431 sendWithRepeatAndSeat(Key action, int keyCode, Display display, int repeatCount, int seat)1432 private KeyEvent sendWithRepeatAndSeat(Key action, int keyCode, Display display, 1433 int repeatCount, int seat) { 1434 KeyEvent event = new KeyEvent( 1435 /* downTime= */ 0L, 1436 /* eventTime= */ 0L, 1437 action == Key.DOWN ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP, 1438 keyCode, 1439 repeatCount); 1440 event.setDisplayId(INVALID_DISPLAY); 1441 mCarInputService.onKeyEvent( 1442 event, 1443 display == Display.MAIN 1444 ? CarOccupantZoneManager.DISPLAY_TYPE_MAIN 1445 : CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER, 1446 seat); 1447 return event; 1448 } 1449 registerProjectionKeyEventHandler( int... events)1450 private CarProjectionManager.ProjectionKeyEventHandler registerProjectionKeyEventHandler( 1451 int... events) { 1452 BitSet eventSet = new BitSet(); 1453 for (int event : events) { 1454 eventSet.set(event); 1455 } 1456 1457 CarProjectionManager.ProjectionKeyEventHandler projectionKeyEventHandler = 1458 mock(CarProjectionManager.ProjectionKeyEventHandler.class); 1459 mCarInputService.setProjectionKeyEventHandler(projectionKeyEventHandler, eventSet); 1460 return projectionKeyEventHandler; 1461 } 1462 flushHandler()1463 private void flushHandler() { 1464 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); 1465 1466 verify(mHandler, atLeast(0)).sendMessageAtTime(messageCaptor.capture(), anyLong()); 1467 1468 for (Message message : messageCaptor.getAllValues()) { 1469 mHandler.dispatchMessage(message); 1470 } 1471 1472 clearInvocations(mHandler); 1473 } 1474 mockEnableLongPressBluetoothVoiceRecognitionProperty(boolean enabledOrNot)1475 private void mockEnableLongPressBluetoothVoiceRecognitionProperty(boolean enabledOrNot) { 1476 when(mMockResources.getBoolean(R.bool.enableLongPressBluetoothVoiceRecognition)) 1477 .thenReturn(enabledOrNot); 1478 } 1479 mockEnableLongPressBluetoothPairingProperty(boolean enabledOrNot)1480 private void mockEnableLongPressBluetoothPairingProperty(boolean enabledOrNot) { 1481 when(mMockResources.getBoolean(R.bool.config_enableLongPressBluetoothPairing)) 1482 .thenReturn(enabledOrNot); 1483 } 1484 } 1485