Android13 InputHalService onHalEvents流程分析

在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方法了。

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值