转自: http://blog.csdn.net/a345017062/article/details/6417929
Android2.3的输入事件流程与以前版本有了较大的不同,这里做一下详细的分析,最后我把自己分析时用的演示代码放在了这里:
http://code.google.com/p/flying-on-android/
下面的分析都是基于这些源码的,大家可以下载下来一边看源码一边看文档。源码里只要关注FlyingEvent这个类就可以了。如果只想看一下演示结果,可以直接把包里的flying放到机器的/system/bin目录执行,打开logcat后就可以看到演示输出。运行程序时,机器屏幕会有异象产生,很正常,因为这个程序原本是用于显示SurfaceFlinger的,这次为了演示EventHub稍微改了一下。大家只要关注FlyingEvent.cpp这个文件就好了。
大家也可以用源码自己编译出演示程序,只要把解压后的flying文件夹放到/frameworks/base/cmds/目录下,然后切换到flying目录下使用mm编译。
先大致介绍一下整个流程,再做重点分析。输入事件流程一共涉及到下面这几个文件:
/frameworks/base/services/java/com/android/server/WindowManagerService.java
/frameworks/base/services/java/com/android/server/InputManager.java
/frameworks/base/services/jni/com_android_server_InputManager.cpp
/frameworks/base/libs/ui/InputReader.cpp
/frameworks/base/libs/ui/InputDispatcher.cpp
/frameworks/base/libs/ui/EventHub.cpp
其中,WindowManagerService.java和InputManager.java主要向Android为窗口系统提供服务,EventHub.cpp主要用来读取设备文件中的RawEvent,而InputReader.cpp和InputDispatcher.cpp算是它们之间的对接层。
它们的关系是:WindowManagerService通过InputManager提供的接口开启一个线程驱动InputReader不断地从/dev/input/目录下面的设备文件读取事件,然后通过InputDispatcher分发给连接到WindowManagerService服务的客户端。
InputReader从设备文件中读取的是RawEvent,在交给InputDispatcher进行分发之前,它需要先把RawEvent进行转化分类,拆分成KeyEvent、MotionEvent、TrackEvent各种类型等。这篇文章主要关注的就是这个RawEvent的拆分过程,所以我们的重点在EventHub.cpp中。并且,为了简单化分析过程,在这里我的分析只关注触摸屏事件。看它是如何从RawEvent被拆分成应用层用户事件MotionEvent的。
看下面的分析之前,最好先去上面提到的地址把源码下载下来,参照里面的FlyingEvent.cpp。
整个过程大致分成这么几步:
一、初始化。
先new一个EventHub的实例:mEventHub(new EventHub),
接下来,开启一个线程通过mEventHub不停地从设备文件中读取RawEvent并处理:
while (1) {
RawEvent event;
mEventHub->getEvent(&event);
process(event);
}
EventHub在初始化的时候做一些事情,
1、搜索当前的输入设备每搜索到一个就会产生一个类型为DEVICE_ADDED的事件,当读取这种RawEvent时,InputReader会把搜索到的这个设备记录下来。
2、如果搜索到了键盘时,就会加载键盘布局文件。加载完成后产生一个类型为FINISHED_DEVICE_SCAN的事件。这样,后边从驱动读取用户按键时,就会去加载的键盘布局文件中寻找映射的键值封装成KeyEvent返回给用户。
二、EventHub初始化完毕后,就开始等待用户输入。线程一直阻塞在mEventHub->getEvent(&event),直到有用户事件产生才会返回。
当有一个事件产生时,传递给process进行处理。
三、事件拆分
FlyingEvent.process里面主要调用了FlyingEvent.consume方法来处理用户事件。这里只分析touch事件。touch事件可以分为三种:down,move,up。
down类型的touch事件需要四个RawEvent来完成,第一个是X坐标(ABS_X),第二个是Y坐标(ABS_Y),第三个代表方向(ABS_PRESSURE)(0的时候是up,1的时候是down,所以这里应该是1),第四个是结束标志(SYN_REPORT)。
move类型的touch事件需要三个RawEvent来完成,第一个是X坐标,第二个是Y坐标,第三个是结束标志。
up类型的touch事件需要两个RawEvent来完成,第一个代表方向(0的时候是up,1的时候是down,所以这里应该是0),第四个是结束标志。
可能你已经注意到了up事件是没有坐标信息的,它的坐标信息与down(没有move时)或最后一个move(down和up之间有move事件产生)事件的坐标相同。
从FlyingEvent.consume方法中,每一个事件最终都会生成一个TouchEvent,然后调用printTouchEvent进行打印,最后把它存储到eventBuffer中。
参考文章
李先静的“Android输入事件流程“,不过使用的Android版本比较老了。
http://blog.csdn.net/absurd/archive/2009/05/17/4195363.aspx