blob: abd5b640920040a00b2d69ac394fc6131454f5e3 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.car.input;
import static android.car.CarOccupantZoneManager.DisplayTypeEnum;
import static android.hardware.automotive.vehicle.V2_0.CustomInputType.CUSTOM_EVENT_F1;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.testng.Assert.assertThrows;
import android.annotation.NonNull;
import android.car.Car;
import android.car.CarOccupantZoneManager;
import android.car.input.CarInputManager;
import android.car.input.CustomInputEvent;
import android.car.input.RotaryEvent;
import android.hardware.automotive.vehicle.V2_0.RotaryInputType;
import android.hardware.automotive.vehicle.V2_0.VehicleDisplay;
import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
import android.os.SystemClock;
import android.util.Log;
import android.util.Pair;
import android.view.KeyEvent;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
import com.android.car.CarServiceUtils;
import com.android.car.MockedCarTestBase;
import com.android.car.vehiclehal.VehiclePropValueBuilder;
import com.android.internal.annotations.GuardedBy;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
@MediumTest
public final class CarInputManagerTest extends MockedCarTestBase {
private static final String TAG = CarInputManagerTest.class.getSimpleName();
private static final int INVALID_DISPLAY_TYPE = -1;
private static final int INVALID_INPUT_TYPE = -1;
private CarInputManager mCarInputManager;
private final class CaptureCallback implements CarInputManager.CarInputCaptureCallback {
private static final long EVENT_WAIT_TIME = 5_000;
private final Object mLock = new Object();
private final String mName;
private CaptureCallback(String name) {
mName = name;
}
// Stores passed events. Last one in front
@GuardedBy("mLock")
private final LinkedList<Pair<Integer, List<KeyEvent>>> mKeyEvents = new LinkedList<>();
// Stores passed events. Last one in front
@GuardedBy("mLock")
private final LinkedList<Pair<Integer, List<RotaryEvent>>> mRotaryEvents =
new LinkedList<>();
// Stores passed events. Last one in front
@GuardedBy("mLock")
private final LinkedList<Pair<Integer, List<CustomInputEvent>>> mCustomInputEvents =
new LinkedList<>();
// Stores passed state changes. Last one in front
@GuardedBy("mLock")
private final LinkedList<Pair<Integer, int[]>> mStateChanges = new LinkedList<>();
private final Semaphore mKeyEventWait = new Semaphore(0);
private final Semaphore mRotaryEventWait = new Semaphore(0);
private final Semaphore mStateChangeWait = new Semaphore(0);
private final Semaphore mCustomInputEventWait = new Semaphore(0);
@Override
public void onKeyEvents(@DisplayTypeEnum int targetDisplayType,
@NonNull List<KeyEvent> keyEvents) {
Log.i(TAG, "onKeyEvents event:" + keyEvents.get(0) + " this:" + this);
synchronized (mLock) {
mKeyEvents.addFirst(new Pair<>(targetDisplayType, keyEvents));
}
mKeyEventWait.release();
}
@Override
public void onRotaryEvents(@DisplayTypeEnum int targetDisplayType,
@NonNull List<RotaryEvent> events) {
Log.i(TAG, "onRotaryEvents event:" + events.get(0) + " this:" + this);
synchronized (mLock) {
mRotaryEvents.addFirst(new Pair<>(targetDisplayType, events));
}
mRotaryEventWait.release();
}
@Override
public void onCustomInputEvents(@DisplayTypeEnum int targetDisplayType,
@NonNull List<CustomInputEvent> events) {
Log.i(TAG, "onCustomInputEvents event:" + events.get(0) + " this:" + this);
synchronized (mLock) {
mCustomInputEvents.addFirst(new Pair<>(targetDisplayType, events));
}
mCustomInputEventWait.release();
}
@Override
public void onCaptureStateChanged(@DisplayTypeEnum int targetDisplayType,
@NonNull @CarInputManager.InputTypeEnum int[] activeInputTypes) {
Log.i(TAG, "onCaptureStateChanged types:" + Arrays.toString(activeInputTypes)
+ " this:" + this);
synchronized (mLock) {
mStateChanges.addFirst(new Pair<>(targetDisplayType, activeInputTypes));
}
mStateChangeWait.release();
}
private void resetAllEventsWaiting() {
mStateChangeWait.drainPermits();
mKeyEventWait.drainPermits();
mRotaryEventWait.drainPermits();
}
private void waitForStateChange() throws Exception {
assertWithMessage("Failed to acquire semaphore in %s ms", EVENT_WAIT_TIME).that(
mStateChangeWait.tryAcquire(EVENT_WAIT_TIME, TimeUnit.MILLISECONDS)).isTrue();
}
private void waitForKeyEvent() throws Exception {
assertWithMessage("Failed to acquire semaphore in %s ms", EVENT_WAIT_TIME).that(
mKeyEventWait.tryAcquire(EVENT_WAIT_TIME, TimeUnit.MILLISECONDS)).isTrue();
}
private void waitForRotaryEvent() throws Exception {
assertWithMessage("Failed to acquire semaphore in %s ms", EVENT_WAIT_TIME).that(
mRotaryEventWait.tryAcquire(EVENT_WAIT_TIME, TimeUnit.MILLISECONDS)).isTrue();
}
private void waitForCustomInputEvent() throws Exception {
assertWithMessage("Failed to acquire semaphore in %s ms", EVENT_WAIT_TIME).that(
mCustomInputEventWait.tryAcquire(
EVENT_WAIT_TIME, TimeUnit.MILLISECONDS)).isTrue();
}
private LinkedList<Pair<Integer, List<KeyEvent>>> getkeyEvents() {
synchronized (mLock) {
LinkedList<Pair<Integer, List<KeyEvent>>> r =
new LinkedList<>(mKeyEvents);
Log.i(TAG, "getKeyEvents size:" + r.size() + ",this:" + this);
return r;
}
}
private LinkedList<Pair<Integer, List<RotaryEvent>>> getRotaryEvents() {
synchronized (mLock) {
LinkedList<Pair<Integer, List<RotaryEvent>>> r =
new LinkedList<>(mRotaryEvents);
Log.i(TAG, "getRotaryEvents size:" + r.size() + ",this:" + this);
return r;
}
}
private LinkedList<Pair<Integer, int[]>> getStateChanges() {
synchronized (mLock) {
return new LinkedList<>(mStateChanges);
}
}
private LinkedList<Pair<Integer, List<CustomInputEvent>>> getCustomInputEvents() {
synchronized (mLock) {
LinkedList<Pair<Integer, List<CustomInputEvent>>> r =
new LinkedList<>(mCustomInputEvents);
Log.i(TAG, "getCustomInputEvents size:" + r.size() + ",this:" + this);
return r;
}
}
@Override
public String toString() {
return "CaptureCallback{mName='" + mName + "'}";
}
}
private final CaptureCallback mCallback0 = new CaptureCallback("callback0");
private final CaptureCallback mCallback1 = new CaptureCallback("callback1");
private final CaptureCallback mCallback2 = new CaptureCallback("callback2");
@Override
protected synchronized void configureMockedHal() {
addProperty(VehicleProperty.HW_KEY_INPUT,
VehiclePropValueBuilder.newBuilder(VehicleProperty.HW_KEY_INPUT)
.addIntValue(0, 0, 0)
.build());
addProperty(VehicleProperty.HW_ROTARY_INPUT,
VehiclePropValueBuilder.newBuilder(VehicleProperty.HW_ROTARY_INPUT)
.addIntValue(0, 1, 0)
.build());
addProperty(VehicleProperty.HW_CUSTOM_INPUT,
VehiclePropValueBuilder.newBuilder(VehicleProperty.HW_CUSTOM_INPUT)
.addIntValue(0)
.build());
}
@Override
protected synchronized void configureResourceOverrides(MockResources resources) {
super.configureResourceOverrides(resources);
resources.overrideResource(com.android.car.R.string.config_clusterHomeActivity,
getTestContext().getPackageName() + "/" + CarInputManagerTest.class.getName());
}
@Override
public void setUp() throws Exception {
super.setUp();
mCarInputManager = (CarInputManager) getCar().getCarManager(Car.CAR_INPUT_SERVICE);
assertThat(mCarInputManager).isNotNull();
}
@Test
public void testInvalidArgs() {
// Invalid display
assertThrows(IllegalArgumentException.class,
() -> mCarInputManager.requestInputEventCapture(INVALID_DISPLAY_TYPE,
new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0, mCallback0));
// Invalid input types
assertThrows(IllegalArgumentException.class,
() -> mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, INVALID_INPUT_TYPE},
0, mCallback0));
assertThrows(IllegalArgumentException.class,
() -> mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION},
CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, mCallback0));
assertThrows(IllegalArgumentException.class,
() -> mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN, new int[]{INVALID_INPUT_TYPE},
0, mCallback0));
assertThrows(IllegalArgumentException.class,
() -> mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, INVALID_INPUT_TYPE},
0, mCallback0));
}
private CarInputManager createAnotherCarInputManager() {
return (CarInputManager) createNewCar().getCarManager(Car.CAR_INPUT_SERVICE);
}
@Test
public void testInjectKeyEvent_mainDisplay() throws Exception {
int r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
KeyEvent keyEvent = newKeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
mCarInputManager.injectKeyEvent(keyEvent, CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
mCallback0.waitForKeyEvent();
assertThat(mCallback0.getkeyEvents()).containsExactly(
new Pair<>(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
Collections.singletonList(keyEvent)));
}
@Test
public void testInjectKeyEvent_instrumentClusterDisplay() throws Exception {
int r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER,
new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
KeyEvent keyEvent = newKeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
mCarInputManager.injectKeyEvent(keyEvent,
CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER);
mCallback0.waitForKeyEvent();
assertThat(mCallback0.getkeyEvents()).containsExactly(
new Pair<>(CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER,
Collections.singletonList(keyEvent)));
}
private static KeyEvent newKeyEvent(int action, int code) {
long currentTime = SystemClock.uptimeMillis();
return new KeyEvent(/* downTime= */ currentTime,
/* eventTime= */ currentTime, action, code,
/* repeat= */ 0);
}
@Test
public void testFailWithFullCaptureHigherPriority() {
CarInputManager carInputManager0 = createAnotherCarInputManager();
int r = carInputManager0.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
//TODO(b/151225008) test event
r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0, mCallback1);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_FAILED);
carInputManager0.releaseInputEventCapture(CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0, mCallback1);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
//TODO(b/151225008) test event
}
@Test
public void testDelayedGrantWithFullCapture() throws Exception {
mCallback1.resetAllEventsWaiting();
CarInputManager carInputManager0 = createAnotherCarInputManager();
int r = carInputManager0.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
injectKeyEvent(true, KeyEvent.KEYCODE_NAVIGATE_NEXT);
waitAndAssertLastKeyEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, true,
KeyEvent.KEYCODE_NAVIGATE_NEXT, mCallback0);
injectKeyEvent(true, KeyEvent.KEYCODE_DPAD_CENTER);
waitAndAssertLastKeyEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, true,
KeyEvent.KEYCODE_DPAD_CENTER, mCallback0);
int numClicks = 3;
injectRotaryNavigationEvent(VehicleDisplay.MAIN, numClicks);
waitAndAssertLastRotaryEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, numClicks, mCallback0);
r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION},
CarInputManager.CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT, mCallback1);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_DELAYED);
injectRotaryNavigationEvent(VehicleDisplay.MAIN, numClicks);
waitForDispatchToMain();
assertNumberOfOnRotaryEvents(0, mCallback1);
carInputManager0.releaseInputEventCapture(CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
// Now capture should be granted back
waitAndAssertLastStateChange(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION},
mCallback1);
assertNoStateChange(mCallback0);
injectRotaryNavigationEvent(VehicleDisplay.MAIN, numClicks);
waitAndAssertLastRotaryEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, numClicks, mCallback1);
}
@Test
public void testOneClientTransitionFromFullToNonFull() throws Exception {
CarInputManager carInputManager0 = createAnotherCarInputManager();
int r = carInputManager0.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION,
CarInputManager.INPUT_TYPE_NAVIGATE_KEYS},
CarInputManager.CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT, mCallback1);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_DELAYED);
r = carInputManager0.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION,
CarInputManager.INPUT_TYPE_DPAD_KEYS}, 0, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
waitForDispatchToMain();
waitAndAssertLastStateChange(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_NAVIGATE_KEYS},
mCallback1);
assertNoStateChange(mCallback0);
}
@Test
public void testSwitchFromFullCaptureToPerTypeCapture() {
int r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0, mCallback1);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_CUSTOM_INPUT_EVENT}, 0, mCallback2);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
}
@Test
public void testIndependentTwoCaptures() throws Exception {
int r = createAnotherCarInputManager().requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
int numClicks = 3;
injectRotaryNavigationEvent(VehicleDisplay.MAIN, numClicks);
waitAndAssertLastRotaryEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, numClicks, mCallback0);
r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_NAVIGATE_KEYS}, 0, mCallback1);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
injectKeyEvent(true, KeyEvent.KEYCODE_NAVIGATE_NEXT);
waitAndAssertLastKeyEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, true,
KeyEvent.KEYCODE_NAVIGATE_NEXT, mCallback1);
}
@Test
public void testTwoClientsOverwrap() throws Exception {
CarInputManager carInputManager0 = createAnotherCarInputManager();
CarInputManager carInputManager1 = createAnotherCarInputManager();
mCallback0.resetAllEventsWaiting();
int r = carInputManager0.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{
CarInputManager.INPUT_TYPE_DPAD_KEYS,
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
injectKeyEvent(true, KeyEvent.KEYCODE_DPAD_CENTER);
waitAndAssertLastKeyEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, true,
KeyEvent.KEYCODE_DPAD_CENTER, mCallback0);
int numClicks = 3;
injectRotaryNavigationEvent(VehicleDisplay.MAIN, numClicks);
waitAndAssertLastRotaryEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, numClicks, mCallback0);
r = carInputManager1.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION,
CarInputManager.INPUT_TYPE_NAVIGATE_KEYS}, 0, mCallback1);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
waitAndAssertLastStateChange(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_DPAD_KEYS},
mCallback0);
assertNoStateChange(mCallback1);
injectKeyEvent(true, KeyEvent.KEYCODE_NAVIGATE_NEXT);
waitAndAssertLastKeyEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, true,
KeyEvent.KEYCODE_NAVIGATE_NEXT, mCallback1);
assertNumberOfOnKeyEvents(1, mCallback0);
injectKeyEvent(true, KeyEvent.KEYCODE_DPAD_CENTER);
waitAndAssertLastKeyEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, true,
KeyEvent.KEYCODE_DPAD_CENTER, mCallback0);
assertNumberOfOnKeyEvents(2, mCallback0);
injectRotaryNavigationEvent(VehicleDisplay.MAIN, numClicks);
waitAndAssertLastRotaryEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, numClicks, mCallback1);
assertNumberOfOnRotaryEvents(1, mCallback0);
mCallback0.resetAllEventsWaiting();
carInputManager1.releaseInputEventCapture(CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
waitAndAssertLastStateChange(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_DPAD_KEYS,
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION},
mCallback0);
assertNoStateChange(mCallback1);
injectRotaryNavigationEvent(VehicleDisplay.MAIN, numClicks);
waitAndAssertLastRotaryEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, numClicks, mCallback0);
}
@Test
public void testInteractionWithFullCapturer() throws Exception {
CarInputManager carInputManager0 = createAnotherCarInputManager();
CarInputManager carInputManager1 = createAnotherCarInputManager();
// Request rotary and dpad input event capture for display main (mCallback0)
int r = carInputManager0.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{
CarInputManager.INPUT_TYPE_DPAD_KEYS,
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
// Request all input event capture for display main (mCallback1)
r = carInputManager1.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, mCallback1);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
waitForDispatchToMain();
waitAndAssertLastStateChange(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[0], mCallback0);
assertNoStateChange(mCallback1);
// Release input event capture for main display
carInputManager1.releaseInputEventCapture(CarOccupantZoneManager.DISPLAY_TYPE_MAIN);
waitForDispatchToMain();
waitAndAssertLastStateChange(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_DPAD_KEYS,
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION},
mCallback0);
assertNoStateChange(mCallback1);
}
@Test
public void testFullCapturerAcceptsNotMappedKey() throws Exception {
int r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER,
new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
injectKeyEvent(true, KeyEvent.KEYCODE_MENU, VehicleDisplay.INSTRUMENT_CLUSTER);
waitAndAssertLastKeyEvent(CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER, true,
KeyEvent.KEYCODE_MENU, mCallback0);
}
@Test
public void testSingleClientUpdates() {
int r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{
CarInputManager.INPUT_TYPE_DPAD_KEYS,
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{
CarInputManager.INPUT_TYPE_DPAD_KEYS,
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
waitForDispatchToMain();
assertNoStateChange(mCallback0);
r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{
CarInputManager.INPUT_TYPE_DPAD_KEYS,
CarInputManager.INPUT_TYPE_NAVIGATE_KEYS}, 0, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
waitForDispatchToMain();
assertNoStateChange(mCallback0);
r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
waitForDispatchToMain();
assertNoStateChange(mCallback0);
r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
waitForDispatchToMain();
assertNoStateChange(mCallback0);
}
@Test
public void testInjectingRotaryEventAndExecutor() throws Exception {
// Arrange executors to process events
Executor rotaryExecutor = spy(Executors.newSingleThreadExecutor());
// Arrange: register callback
CarInputManager carInputManager = createAnotherCarInputManager();
int r = carInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION}, 0, rotaryExecutor,
mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
// Act: inject RotaryEvent
int numClicks = 3;
injectRotaryNavigationEvent(VehicleDisplay.MAIN, numClicks);
// Assert: ensure RotaryEvent was delivered
waitAndAssertLastRotaryEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
CarInputManager.INPUT_TYPE_ROTARY_NAVIGATION, numClicks, mCallback0);
// Assert: ensure that Rotary event was dispatched using the assigned executor
verify(rotaryExecutor).execute(any(Runnable.class));
}
@Test
public void testInjectingKeyEventAndExecutor() throws Exception {
// Arrange executors to process events
Executor keyEventExecutor = spy(Executors.newSingleThreadExecutor());
// Arrange: register callback
CarInputManager carInputManager = createAnotherCarInputManager();
int r = carInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_NAVIGATE_KEYS}, 0, keyEventExecutor,
mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
// Act: inject KeyEvent
injectKeyEvent(true, KeyEvent.KEYCODE_NAVIGATE_NEXT);
// Assert: ensure KeyEvent was delivered
waitAndAssertLastKeyEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, true,
KeyEvent.KEYCODE_NAVIGATE_NEXT, mCallback0);
// Assert: ensure that Key event was dispatched using the assigned executor
verify(keyEventExecutor).execute(any(Runnable.class));
}
@Test
public void testInjectingCustomInputEventAndExecutor() throws Exception {
// Arrange executors to process events
Executor customInputEventExecutor = spy(Executors.newSingleThreadExecutor());
// Arrange: register callback
CarInputManager carInputManager = createAnotherCarInputManager();
int r = carInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_CUSTOM_INPUT_EVENT}, 0,
customInputEventExecutor, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
// Act: inject CustomInputEvent
int repeatedCounter = 1;
injectCustomInputEvent(CUSTOM_EVENT_F1, VehicleDisplay.MAIN,
/* repeatCounter= */ repeatedCounter);
// Assert: ensure CustomInputEvent was delivered
waitAndAssertLastCustomInputEvent(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, CUSTOM_EVENT_F1,
repeatedCounter, mCallback0);
// Assert: ensure that CustomInputEvent was dispatched using the assigned executor
verify(customInputEventExecutor).execute(any(Runnable.class));
}
@Test
public void testRotaryVolumeTypeIsNotSupportedYet() {
assertThrows(IllegalArgumentException.class,
() -> mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_ROTARY_VOLUME}, 0, mCallback0));
}
@Test
public void testCallbacksForDifferentDisplays_keyInputEvents_mainDisplay() throws Exception {
registerCallbackForAllInputs(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, mCallback0);
registerCallbackForAllInputs(CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER,
mCallback1);
sendAndAssertKeyEvent(KeyEvent.KEYCODE_HOME, CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
mCallback0);
assertNoKeyEventSent(mCallback1);
}
@Test
public void testCallbacksForDifferentDisplays_keyInputEvents_clusterDisplay() throws Exception {
registerCallbackForAllInputs(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, mCallback0);
registerCallbackForAllInputs(CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER,
mCallback1);
sendAndAssertKeyEvent(KeyEvent.KEYCODE_HOME,
CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER,
mCallback1);
assertNoKeyEventSent(mCallback0);
}
@Test
public void testCallbacksForDifferentDisplays_customInputEvents_mainDisplay() throws Exception {
registerCallbackForAllInputs(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, mCallback0);
registerCallbackForAllInputs(CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER,
mCallback1);
sendAndAssertCustomInputEvent(CUSTOM_EVENT_F1,
CarOccupantZoneManager.DISPLAY_TYPE_MAIN, /* repeatedCounter= */ 1,
mCallback0);
assertNoCustomInputEventSent(mCallback1);
}
@Test
public void testCallbacksForDifferentDisplays_customInputEvents_clusterDisplay()
throws Exception {
registerCallbackForAllInputs(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, mCallback0);
registerCallbackForAllInputs(CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER,
mCallback1);
sendAndAssertCustomInputEvent(CUSTOM_EVENT_F1,
CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER, /* repeatedCounter= */ 1,
mCallback1);
assertNoCustomInputEventSent(mCallback0);
}
@Test
public void testCallbacksForDifferentDisplays_rotaryEvents_mainDisplay() throws Exception {
registerCallbackForAllInputs(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, mCallback0);
registerCallbackForAllInputs(CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER,
mCallback1);
sendAndAssertRotaryNavigationEvent(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN, /* numClicks= */ 1,
mCallback0);
assertNoRotaryEventSent(mCallback1);
}
@Test
public void testCallbacksForDifferentDisplays_rotaryEvents_clusterDisplay() throws Exception {
registerCallbackForAllInputs(CarOccupantZoneManager.DISPLAY_TYPE_MAIN, mCallback0);
registerCallbackForAllInputs(CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER,
mCallback1);
sendAndAssertRotaryNavigationEvent(
CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER, /* numClicks= */ 1,
mCallback1);
assertNoRotaryEventSent(mCallback0);
}
private void registerCallbackForAllInputs(int displayType, CaptureCallback callback) {
int respMain = mCarInputManager.requestInputEventCapture(
displayType,
new int[]{CarInputManager.INPUT_TYPE_ALL_INPUTS},
CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY, callback);
assertThat(respMain).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
}
@Test
public void testInputTypeSystemNavigateKeys() throws Exception {
int r = mCarInputManager.requestInputEventCapture(
CarOccupantZoneManager.DISPLAY_TYPE_MAIN,
new int[]{CarInputManager.INPUT_TYPE_SYSTEM_NAVIGATE_KEYS}, 0, mCallback0);
assertThat(r).isEqualTo(CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED);
sendAndAssertKeyEvent(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN,
CarOccupantZoneManager.DISPLAY_TYPE_MAIN, mCallback0);
sendAndAssertKeyEvent(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP,
CarOccupantZoneManager.DISPLAY_TYPE_MAIN, mCallback0);
sendAndAssertKeyEvent(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT,
CarOccupantZoneManager.DISPLAY_TYPE_MAIN, mCallback0);
sendAndAssertKeyEvent(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT,
CarOccupantZoneManager.DISPLAY_TYPE_MAIN, mCallback0);
}
private void sendAndAssertKeyEvent(int keyCode, int displayType, CaptureCallback callback)
throws Exception {
KeyEvent keyEvent = newKeyEvent(KeyEvent.ACTION_DOWN, keyCode);
mCarInputManager.injectKeyEvent(keyEvent, displayType);
callback.waitForKeyEvent();
assertThat(callback.getkeyEvents()).contains(
new Pair<>(displayType,
Collections.singletonList(keyEvent)));
}
private void sendAndAssertCustomInputEvent(int inputCode, int displayType, int repeatedCounter,
CaptureCallback callback)
throws Exception {
injectCustomInputEvent(inputCode,
convertToVehicleDisplay(displayType), repeatedCounter);
callback.waitForCustomInputEvent();
assertThat(callback.getCustomInputEvents()).hasSize(1);
Pair<Integer, List<CustomInputEvent>> customInputEvents =
callback.getCustomInputEvents().get(0);
assertThat(customInputEvents.second).hasSize(1);
CustomInputEvent customInputEvent = customInputEvents.second.get(0);
assertThat(customInputEvent.getInputCode()).isEqualTo(inputCode);
assertThat(customInputEvent.getTargetDisplayType()).isEqualTo(displayType);
assertThat(customInputEvent.getRepeatCounter()).isEqualTo(repeatedCounter);
}
/**
* Utility method to convert CarOccupantZoneManager display type to Vehicle HAL display type
*/
private static int convertToVehicleDisplay(int vehicleDisplayType) {
switch (vehicleDisplayType) {
case CarOccupantZoneManager.DISPLAY_TYPE_MAIN:
return VehicleDisplay.MAIN;
case CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER:
return VehicleDisplay.INSTRUMENT_CLUSTER;
default:
throw new IllegalArgumentException(
"CarOccupantZone display type {" + vehicleDisplayType
+ "} has no equivalent in VehicleDisplay display type");
}
}
private void sendAndAssertRotaryNavigationEvent(int displayType, int numClicks,
CaptureCallback callback)
throws Exception {
injectRotaryNavigationEvent(convertToVehicleDisplay(displayType),
numClicks);
callback.waitForRotaryEvent();
assertThat(callback.getRotaryEvents()).hasSize(1);
Pair<Integer, List<RotaryEvent>> capturedEvents = callback.getRotaryEvents().get(0);
assertThat(capturedEvents.second).hasSize(1);
RotaryEvent rotaryEvent = capturedEvents.second.get(0);
assertThat(rotaryEvent.getNumberOfClicks()).isEqualTo(numClicks);
}
/**
* Events dispatched to main, so this should guarantee that all event dispatched are completed.
*/
private void waitForDispatchToMain() {
// Needs to be invoked twice as it is dispatched to main inside car service once, and it is
// dispatched to main inside CarInputManager once.
CarServiceUtils.runOnMainSync(() -> {});
CarServiceUtils.runOnMainSync(() -> {});
}
private void waitAndAssertLastKeyEvent(int displayTarget, boolean down, int keyCode,
CaptureCallback callback) throws Exception {
// Wait for key event first.
callback.waitForKeyEvent();
LinkedList<Pair<Integer, List<KeyEvent>>> events = callback.getkeyEvents();
assertThat(events).isNotEmpty();
Pair<Integer, List<KeyEvent>> lastEvent = events.getFirst();
assertThat(lastEvent.first).isEqualTo(displayTarget);
assertThat(lastEvent.second).hasSize(1);
KeyEvent keyEvent = lastEvent.second.get(0);
assertThat(keyEvent.getAction()).isEqualTo(
down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP);
assertThat(keyEvent.getKeyCode()).isEqualTo(keyCode);
}
private void assertNumberOfOnKeyEvents(int expectedNumber, CaptureCallback callback) {
LinkedList<Pair<Integer, List<KeyEvent>>> events = callback.getkeyEvents();
assertThat(events).hasSize(expectedNumber);
}
private void waitAndAssertLastRotaryEvent(int displayTarget, int rotaryType, int numberOfClicks,
CaptureCallback callback) throws Exception {
// Wait for rotary event first.
callback.waitForRotaryEvent();
LinkedList<Pair<Integer, List<RotaryEvent>>> rotaryEvents = callback.getRotaryEvents();
assertThat(rotaryEvents).isNotEmpty();
Pair<Integer, List<RotaryEvent>> lastEvent = rotaryEvents.getFirst();
assertThat(lastEvent.first).isEqualTo(displayTarget);
assertThat(lastEvent.second).hasSize(1);
RotaryEvent rotaryEvent = lastEvent.second.get(0);
assertThat(rotaryEvent.getInputType()).isEqualTo(rotaryType);
assertThat(rotaryEvent.getNumberOfClicks()).isEqualTo(numberOfClicks);
// TODO(b/151225008) Test timestamp
}
private void assertNumberOfOnRotaryEvents(int expectedNumber, CaptureCallback callback) {
LinkedList<Pair<Integer, List<RotaryEvent>>> rotaryEvents = callback.getRotaryEvents();
assertThat(rotaryEvents).hasSize(expectedNumber);
}
private void waitAndAssertLastStateChange(int expectedTargetDisplayTarget,
int[] expectedInputTypes, CaptureCallback callback) throws Exception {
// Wait for state change event first.
callback.waitForStateChange();
LinkedList<Pair<Integer, int[]>> changes = callback.getStateChanges();
assertThat(changes).isNotEmpty();
Pair<Integer, int[]> lastChange = changes.getFirst();
assertStateChange(expectedTargetDisplayTarget, expectedInputTypes, lastChange);
}
private void assertNoStateChange(CaptureCallback callback) {
assertThat(callback.getStateChanges()).isEmpty();
}
private void assertNoKeyEventSent(CaptureCallback callback) {
assertThat(callback.getkeyEvents()).isEmpty();
}
private void assertNoCustomInputEventSent(CaptureCallback callback) {
assertThat(callback.getCustomInputEvents()).isEmpty();
}
private void assertNoRotaryEventSent(CaptureCallback callback) {
assertThat(callback.getRotaryEvents()).isEmpty();
}
private void assertStateChange(int expectedTargetDisplayTarget, int[] expectedInputTypes,
Pair<Integer, int[]> actual) {
Arrays.sort(expectedInputTypes);
assertThat(actual.first).isEqualTo(expectedTargetDisplayTarget);
assertThat(actual.second).isEqualTo(expectedInputTypes);
}
private void waitAndAssertLastCustomInputEvent(int expectedDisplayType,
int expectedCustomEventFunction, int expectedRepeatedCounter,
CaptureCallback callback) throws Exception {
// Wait for custom input event first.
callback.waitForCustomInputEvent();
LinkedList<Pair<Integer, List<CustomInputEvent>>> events = callback.getCustomInputEvents();
assertThat(events).isNotEmpty();
Pair<Integer, List<CustomInputEvent>> lastEvent = events.getFirst();
assertThat(lastEvent.first).isEqualTo(expectedDisplayType);
assertThat(lastEvent.second).hasSize(1);
CustomInputEvent event = lastEvent.second.get(0);
assertThat(event.getInputCode()).isEqualTo(expectedCustomEventFunction);
assertThat(event.getRepeatCounter()).isEqualTo(expectedRepeatedCounter);
assertThat(event.getTargetDisplayType()).isEqualTo(expectedDisplayType);
}
private void injectKeyEvent(boolean down, int keyCode) {
injectKeyEvent(down, keyCode, VehicleDisplay.MAIN);
}
private void injectKeyEvent(boolean down, int keyCode, int vehicleDisplayType) {
getHidlMockedVehicleHal().injectEvent(
VehiclePropValueBuilder.newBuilder(VehicleProperty.HW_KEY_INPUT)
.addIntValue(down ? 0 : 1, keyCode, vehicleDisplayType)
.build());
}
private void injectRotaryNavigationEvent(int displayTarget, int numClicks) {
VehiclePropValueBuilder builder = VehiclePropValueBuilder.newBuilder(
VehicleProperty.HW_ROTARY_INPUT)
.addIntValue(RotaryInputType.ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION, numClicks,
displayTarget);
for (int i = 0; i < numClicks - 1; i++) {
builder.addIntValue(0);
}
getHidlMockedVehicleHal().injectEvent(builder.build());
}
private void injectCustomInputEvent(int inputCode, int targetDisplayType, int repeatCounter) {
VehiclePropValueBuilder builder = VehiclePropValueBuilder.newBuilder(
VehicleProperty.HW_CUSTOM_INPUT)
.addIntValue(inputCode).addIntValue(targetDisplayType).addIntValue(repeatCounter);
getHidlMockedVehicleHal().injectEvent(builder.build());
}
}