0. 背景

M01 中盘控事件是在 WindowManager 中把事件广播出去,需要的 App 自己注册广播来接收。我们觉得广播盘控事件方案不够好,理由如下:

基于以上背景,我们设计了一个新的盘控事件分发方案。实现方案是参考 MediaSessionService 事件分发和 View 的事件分发方案。它有以下几个优点:

1. Android 分发按键事件机制

Android 原生中,KeyEvent 是只分发给当前获得焦点的窗口。

当一个窗口添加到 WindowManager 时,WMS 会创建一对 InputChannel,一个在 InputDispatcher,一个在回传给应用进程中的 ViewRootImpl 中。InputDispatcher 是通过 InputChannel(Socket)把一个输入事件发送给客户端的。

ViewRootImpl 的内部类 WindowInputEventReceiver 继承了 InputEventReceiver,并重写了 onInputEvent() 方法来处理从 InputManager 过来的输入事件。

输入事件的处理是一个责任链模式,其中会调用 View 的 dispatchKeyEvent() 方法。该方法中会调用 KeyEvent 的 dispatch() 方法,这个方法中会处理 mAction,并触发 onKeyDown()onKeyLongPress()onKeyUp() 等回调接口。

2. 盘控分发流程图

当 App 获取 CarKeyManager 时会注册一个 ICarKeyListener 到 CarKeyManagerService 中。当有盘控事件时,CarKeyManagerService 通过 Binder 把事件传递给 CarKeyManager,然后会按照责任链模式依次把事件发给事件处理器 OnKeyEventListener、OnKeyClickListener 和 OnKeyLongClickListener。

UML diagram.jpg

OnKeyEventListener 是从 Service 接收 Key Event 后第一个回调的接口。

如果 onKeyEvent() 方法返回 true,本次盘控分发流程结束。如果返回 false,则会根据 ACTION_UP 的时间调用 onKeyClick()onKeyLongClick()

UML diagram (1).jpg