M01 中盘控事件是在 WindowManager 中把事件广播出去,需要的 App 自己注册广播来接收。我们觉得广播盘控事件方案不够好,理由如下:
基于以上背景,我们设计了一个新的盘控事件分发方案。实现方案是参考 MediaSessionService 事件分发和 View 的事件分发方案。它有以下几个优点:
onKeyEvent()
回调接口,也提供类似于 Touch 的 onKeyClick()
和 onKeyLongClick()
等接口。Android 原生中,KeyEvent 是只分发给当前获得焦点的窗口。
当一个窗口添加到 WindowManager 时,WMS 会创建一对 InputChannel,一个在 InputDispatcher,一个在回传给应用进程中的 ViewRootImpl 中。InputDispatcher 是通过 InputChannel(Socket)把一个输入事件发送给客户端的。
ViewRootImpl 的内部类 WindowInputEventReceiver 继承了 InputEventReceiver,并重写了 onInputEvent()
方法来处理从 InputManager 过来的输入事件。
输入事件的处理是一个责任链模式,其中会调用 View 的 dispatchKeyEvent()
方法。该方法中会调用 KeyEvent 的 dispatch()
方法,这个方法中会处理 mAction,并触发 onKeyDown()
、onKeyLongPress()
、onKeyUp()
等回调接口。
当 App 获取 CarKeyManager 时会注册一个 ICarKeyListener 到 CarKeyManagerService 中。当有盘控事件时,CarKeyManagerService 通过 Binder 把事件传递给 CarKeyManager,然后会按照责任链模式依次把事件发给事件处理器 OnKeyEventListener、OnKeyClickListener 和 OnKeyLongClickListener。
OnKeyEventListener 是从 Service 接收 Key Event 后第一个回调的接口。
如果 onKeyEvent()
方法返回 true,本次盘控分发流程结束。如果返回 false,则会根据 ACTION_UP 的时间调用 onKeyClick()
或 onKeyLongClick()
。