在Vehicle章节,我们分析了Vehicle事件分发流程,在VehicleHal的onPropertyEvent中调用调用各个HalService的onHalEvents,如PowerHalService、PropertyHalService、InputHalService,之后由不同HalService继续对PropertyEvent进行处理。
我们继续分析InputHalService的onHalEvents:
//packages/services/Car/service/src/com/android/car/hal/InputHalService.java
public class InputHalService extends HalServiceBase {
public void onHalEvents(List<HalPropValue> values) {
InputListener listener;
synchronized (mLock) {
listener = mListener;
}
if (listener == null) {
Slogf.w(TAG, "Input event while listener is null");
return;
}
for (int i = 0; i < values.size(); i++) {
HalPropValue value = values.get(i);
switch (value.getPropId()) {
case HW_KEY_INPUT:
dispatchKeyInput(listener, value);
break;
case HW_ROTARY_INPUT:
dispatchRotaryInput(listener, value);
break;
case HW_CUSTOM_INPUT:
dispatchCustomInput(listener, value);
break;
default:
Slogf.e(TAG, "Wrong event dispatched, prop:0x%x", value.getPropId());
break;
}
}
}
}
在onHalEvents中会调用dispatchKeyInput方法:
//packages/services/Car/service/src/com/android/car/hal/InputHalService.java
public class InputHalService extends HalServiceBase {
private void dispatchKeyInput(InputListener listener, HalPropValue value) {
int action;
int code;
int vehicleDisplay;
int indentsCount;
try {
action = (value.getInt32Value(0) == VehicleHwKeyInputAction.ACTION_DOWN)
? KeyEvent.ACTION_DOWN
: KeyEvent.ACTION_UP;
code = value.getInt32Value(1);
vehicleDisplay = value.getInt32Value(2);
indentsCount = value.getInt32ValuesSize() < 4 ? 1 : value.getInt32Value(3);
Slogf.d(TAG, "hal event code: %d, action: %d, display: %d, number of indents: %d",
code, action, vehicleDisplay, indentsCount);
} catch (IndexOutOfBoundsException e) {
Slogf.e(TAG, "Invalid hal key input event received, int32Values: "
+ value.dumpInt32Values(), e);
return;
}
while (indentsCount > 0) {
indentsCount--;
dispatchKeyEvent(listener, action, code, convertDisplayType(vehicleDisplay));
}
}
}
在dispatchKeyInput方法中调用dispatchKeyEvent方法:
//packages/services/Car/service/src/com/android/car/hal/InputHalService.java
public class InputHalService extends HalServiceBase {
private void dispatchKeyEvent(InputListener listener, int action, int code,
@DisplayTypeEnum int display, long eventTime) {
long downTime;
int repeat;
synchronized (mKeyStates) {
KeyState state = mKeyStates.get(code);
if (state == null) {
state = new KeyState();
mKeyStates.put(code, state);
}
if (action == KeyEvent.ACTION_DOWN) {
downTime = eventTime;
repeat = state.mRepeatCount++;
state.mLastKeyDownTimestamp = eventTime;
} else {
// Handle key up events without any matching down event by setting the down time to
// the event time. This shouldn't happen in practice - keys should be pressed
// before they can be released! - but this protects us against HAL weirdness.
downTime =
(state.mLastKeyDownTimestamp == -1)
? eventTime
: state.mLastKeyDownTimestamp;
repeat = 0;
state.mRepeatCount = 0;
}
}
KeyEvent event = new KeyEvent(
downTime,
eventTime,
action,
code,
repeat,
0 /* deviceId */,
0 /* scancode */,
0 /* flags */,
InputDevice.SOURCE_CLASS_BUTTON);
// event.displayId will be set in CarInputService#onKeyEvent
listener.onKeyEvent(event, display); //调用监听器的onKeyEvent,通知按键事件
}
}
调用listener(InputListener)的onKeyEvent方法,
//packages/services/Car/service/src/com/android/car/CarInputService.java
public class CarInputService extends ICarInput.Stub
implements CarServiceBase, InputHalService.InputListener {
public void onKeyEvent(KeyEvent event, @DisplayTypeEnum int targetDisplayType) {
// Special case key code that have special "long press" handling for automotive
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_VOICE_ASSIST:
handleVoiceAssistKey(event);
return;
case KeyEvent.KEYCODE_CALL:
handleCallKey(event);
return;
default:
break;
}
assignDisplayId(event, targetDisplayType);
// Allow specifically targeted keys to be routed to the cluster
if (targetDisplayType == CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER
&& handleInstrumentClusterKey(event)) {
return;
}
if (mCaptureController.onKeyEvent(targetDisplayType, event)) {
return;
}
mMainDisplayHandler.onKeyEvent(event);
}
}
调用mCaptureController(InputCaptureClientController)的onKeyEvent方法:
//packages/services/Car/service/src/com/android/car/InputCaptureClientController.java
public class InputCaptureClientController {
public boolean onKeyEvent(@DisplayTypeEnum int displayType, KeyEvent event) {
if (!SUPPORTED_DISPLAY_TYPES.contains(displayType)) {
return false;
}
Integer inputType = KEY_EVENT_TO_INPUT_TYPE.get(event.getKeyCode());
if (inputType == null) { // not supported key
inputType = CarInputManager.INPUT_TYPE_ALL_INPUTS;
}
ICarInputCallback callback;
synchronized (mLock) {
callback = getClientForInputTypeLocked(displayType, inputType);
if (callback == null) {
return false;
}
mNumKeyEventsDispatched++;
}
dispatchKeyEvent(displayType, event, callback);
return true;
}
}
调用InputCaptureClientController的dispatchKeyEvent方法:
//packages/services/Car/service/src/com/android/car/InputCaptureClientController.java
public class InputCaptureClientController {
private void dispatchKeyEvent(int targetDisplayType, KeyEvent event,
ICarInputCallback callback) {
CarServiceUtils.runOnCommon(() -> {
mKeyEventDispatchScratchList.clear();
mKeyEventDispatchScratchList.add(event);
try {
callback.onKeyEvents(targetDisplayType, mKeyEventDispatchScratchList);
} catch (RemoteException e) {
if (DBG_DISPATCH) {
Slogf.e(TAG, "Failed to dispatch KeyEvent " + event, e);
}
}
});
}
}
调用callback(ICarInputCallback)的dispatchKeyEvent方法,ICarInputCallback是个接口,由ICarInputCallbackImpl实现:
//packages/services/Car/car-lib/src/android/car/input/CarInputManager.java
public final class CarInputManager extends CarManagerBase {
private static final class ICarInputCallbackImpl extends ICarInputCallback.Stub {
@Override
public void onKeyEvents(@DisplayTypeEnum int targetDisplayType,
@NonNull List<KeyEvent> keyEvents) {
CarInputManager manager = mManager.get();
if (manager == null) {
return;
}
manager.dispatchKeyEvents(targetDisplayType, keyEvents);
}
}
}
调用manager(CarInputManager)的dispatchKeyEvents方法:
//packages/services/Car/car-lib/src/android/car/input/CarInputManager.java
public final class CarInputManager extends CarManagerBase {
private static final class CallbackHolder {
final CarInputCaptureCallback mCallback;
final Executor mExecutor;
CallbackHolder(CarInputCaptureCallback callback, Executor executor) {
mCallback = callback;
mExecutor = executor;
}
}
private void dispatchKeyEvents(@DisplayTypeEnum int targetDisplayType,
List<KeyEvent> keyEvents) {
CallbackHolder callbackHolder = getCallback(targetDisplayType);
if (callbackHolder == null) {
return;
}
callbackHolder.mExecutor.execute(() -> {
callbackHolder.mCallback.onKeyEvents(targetDisplayType, keyEvents);
});
}
}
调用callbackHolder.mCallback(CarInputCaptureCallback)的onKeyEvents方法,CarInputCaptureCallback是一个接口,当app调用CarInputManager的requestInputEventCapture时传入,之后就调用到App的Callback方法了。