【Android源码 栏目提醒】:网学会员--在 Android源码 编辑为广大网友搜集整理了:Android键盘系统浅析(上) - 综合课件绩等信息,祝愿广大网友取得需要的信息,参考学习。
Android中的键盘系统的生命周期从系统的启动开始到系统的关闭一直存在着因为在这整个过程中我们希望按下的没一个按键都会有相应的事件发生。
通 过调研发现
Android键盘系统贯穿着
Android框架的最底层——Linux内核驱动到上层JAVA架构层——SystemServer。
与
android键盘系统关系紧密的几个文件从下层往上层依次为Goldfish_event.c处于Linux内核、 EventHub.cpp硬件抽象层、com_
android_server_KeyInputQueue.cppJNI本地方 法KeyInputQueue.java、WindowManagerService.javajava框架层。
发现一个很有意思的问 题
Android并没有做一个纯的键盘系统而是将键盘系统的实现放在了事件处理模块之中。
这从这几个关键文件的文件名我们不难看出。
从上往下的调用过程分析如下 在WindowManagerService.java中启动了窗口管理其中有一个语句如下 mQueue new KeyQ 追踪到 KeyQ 可知 private class KeyQ extends KeyInputQueue 注在下面的描述中父类是指KeyInputQueue子类是指KeyQ 继续追踪KeyInputQueue 我们会发现这是一个相当庞大的类在这个类中创建了一个线程 Thread mThread new ThreadInputDeviceReader 由构造方法 nbsp nbsp public ThreadString threadName nbsp nbspnbsp nbspnbspnbspif threadName null nbsp nbspnbsp nbspnbsp nbspnbsp nbspthrow new NullPointerException nbsp nbspnbsp nbspnbspnbsp nbsp nbspnbsp nbspnbspnbspcreatenull null threadName 0 我们可以知道Thread mThread new ThreadInputDeviceReader创建了一个名为InputDeviceReader的线程。
但这个线程是怎么创建起来的呢因为我们看到线程对象是在父类中new的。
从父类的
源码中我们可以看到有一个构造方法在这个构造方法中nbspnbsp调用了mThred对象的方法即mThread.start 我们来看看这个构造方法的代码 KeyInputQueueContext context HapticFeedbackCallbacknbspnbsphapticFeedbackCallback nbsp nbspnbsp nbspnbspnbspif MEASURE_LATENCY nbsp nbspnbsp nbspnbsp nbspnbsp nbsplt new LatencyTimer100 1000 nbsp nbspnbsp nbspnbspnbsp nbsp nbspnbsp nbspnbspnbspBAD_TOUCH_HACK context.getResources.getBoolean nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsp com.
android.internal.R.bool.config_filterTouchEvents nbsp nbspnbsp nbspnbspnbsp nbsp nbspnbsp nbspnbspnbspmHapticFeedbackCallback hapticFeedbackCallback nbsp nbspnbsp nbspnbspnbsp nbsp nbspnbsp nbspnbspnbspreadExcludedDevices nbsp nbspnbsp nbspnbspnbsp nbsp nbspnbsp nbspnbspnbspPowerManager pm PowerManagercontext.getSystemService nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspContext.POWER_SERVICE nbsp nbspnbsp nbspnbspnbspmWakeLock pm.newWakeLockPowerManager.PARTIAL_WAKE_LOCK nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspKeyInputQueue nbsp nbspnbsp nbspnbspnbspmWakeLock.setReferenceCountedfalse nbsp nbspnbsp nbspnbspnbspmFirst new QueuedEvent nbsp nbspnbsp nbspnbspnbspmLast new QueuedEvent nbsp nbspnbsp nbspnbspnbspmFirst.next mLast nbsp nbspnbsp nbspnbspnbspmLast.prev mFirst nbsp nbspnbsp nbspnbspnbspmThread.start nbsp nbsp 在子类KeyQ的构造方法中调用了父类的这个构造方法nbsp nbsp private class KeyQ extends KeyInputQueue nbsp nbspnbsp nbspnbsp nbspnbsp nbspimplements KeyInputQueue.FilterCallback nbsp nbspnbsp nbspnbspnbspPowerManager.WakeLock mHoldingScreen //下面是子类KeyQ的构造方法 KeyQ nbsp nbspnbsp nbspnbsp nbspnbsp nbspsupermContext WindowManagerService.this nbsp nbspnbsp nbspnbsp nbspnbsp nbspPowerManager pm PowerManagermContext.getSystemServiceContext.POWER_SERVICE nbsp nbspnbsp nbspnbsp nbspnbsp nbspmHoldingScreen pm.newWakeLockPowerManager.SCREEN_BRIGHT_WAKE_LOCK nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspKEEP_SCREEN_ON_FLAG nbsp nbspnbsp nbspnbsp nbspnbsp nbspmHoldingScreen.setReferenceCountedfalse nbsp nbspnbsp nbspnbspnbsp 自然的就创建了一个父类中的线程mThread。
因此在new一个子类对象的时候 mQueue new KeyQ就调用了父类中的这个线程。
nbsp nbsp nbsp nbsp 在这个线程中调用了本地方法readEvent Thread mThread new ThreadInputDeviceReader nbsp nbspnbsp nbspnbspnbsppublic void run nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp ………………….. nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp RawInputEvent ev new RawInputEvent nbsp nbspnbsp nbspnbsp nbspnbsp nbspwhile true nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsp try nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspInputDevice di nbsp nbspnbsp nbspnbsp nbspnbspnbspnbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp //这是一个本地方法 nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspreadEventev nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp ………………….. nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp 因些我们追踪到该JNI调用com_
android_server_KeyInputQueue.cpp 在该Native方法readEvent中调用了EeventHub.cpp。
………………….. sp hub gHubnbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp //sp是一个类功能是smartpointer ………………….. bool res hub-getEventdeviceId type scancode keycodeflags value when ………………….. 因此我们进入EeventHub.cpp中查看方法getEvevt bool EventHub::getEventint32_t outDeviceId int32_t outType nbsp nbspnbsp nbspnbspnbspint32_t outScancode int32_t outKeycode uint32_t outFlags nbsp nbspnbsp nbspnbspnbspint32_t outValue nsecs_t outWhen 接下来getEvevt中调用了openPlatformInputopenPlatformInput中调用了scan_dirscan_dir中调用了open_device。
我们注意到函数的调用以及进入到EeventHub.cpp这属于硬件抽象层它可以直接对Linux内核驱动进行调用。
我们再回到线程mThread上来在 mQueue new KeyQ 之后接下来调用了 send preprocessEventdi ev 这里实际上是调用了mQueue中的 preprocessEvent。
这是因为子类KeyQ在继承KeyInputQueue时重写了方法preprocessEvent Override nbsp nbspnbsp nbspnbspnbspboolean preprocessEventInputDevice device RawInputEvent event nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp ………………….. nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp 接下来与Key有关的代码有 // Is it a key event nbsp nbspnbsp nbspnbsp nbspif type RawInputEvent.EV_KEY nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspclassesRawInputEvent.CLASS_KEYBOARD 0 nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspscancode RawInputEvent.BTN_LAST nbsp nbspnbsp nbspnbsp nbspnbsp nbsp boolean down nbsp nbspnbsp nbspnbsp nbspnbsp nbsp if ev.value 0 nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspdown true nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspdi.mKeyDownTime curTime nbsp nbspnbsp nbspnbsp nbspnbsp nbsp else nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspdown false nbsp nbspnbsp nbspnbsp nbspnbsp nbsp nbsp nbspnbsp nbspnbsp nbspnbsp nbsp int keycode rotateKeyCodeLockedev.keycode nbsp nbspnbsp nbspnbsp nbspnbsp nbsp addLockeddi curTimeNano ev.flags nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspRawInputEvent.CLASS_KEYBOARD nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnewKeyEventdi di.mKeyDownTime curTime down nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspkeycode 0 scancode nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspev.flags WindowManagerPolicy.FLAG_WOKE_HERE 0 nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsp KeyEvent.FLAG_WOKE_HERE : 0nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsp nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbsp 这mThread之后创建了另外一个线程InputDispatcherThread ………………….. nbsp nbspnbsp nbspnbspnbspmQueue new KeyQ nbsp nbspnbsp nbspnbspnbspmInputThread new InputDispatcherThread nbsp nbspnbsp nbspnbspnbspPolicyThread thr new PolicyThreadmPolicy this context pm nbsp nbspnbsp nbspnbspnbspthr.start ………………….. 在InputDispatcherThread中有关于键盘的一个处理 实际上这个线程是从nbspnbspKeyQ 的事件队列中读取按键事件。
………………….. switch ev.classType nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsp case RawInputEvent.CLASS_KEYBOARD: nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspKeyEvent ke KeyEventev.event nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspif ke.isDown nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsplastKey ke nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspdownTime curTime nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspkeyRepeatCount 0 nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsplastKeyTime curTime nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnextKeyTime lastKeyTime nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbsp ViewConfiguration.getLongPressTimeout nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspif DEBUG_INPUT Log.v nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsp TAG Received key down: first repeat nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsp nextKeyTime nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbsp else nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsplastKey null nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspdownTime 0 nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsp// Arbitrary long timeout. nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsplastKeyTime curTime nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnextKeyTime curTime LONG_WAIT nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspif DEBUG_INPUT Log.v nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsp TAG Received key up: ignore repeat nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbsp nextKeyTime nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbsp nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspdispatchKeyKeyEventev.event 0 0 nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspmQueue.recycleEventev nbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbsp nbspnbspnbspbreak