Step 11.InputDispatcher.dispatchOnceInnerLocked

这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:

  1. voidInputDispatcher::dispatchOnceInnerLocked(nsecs_tkeyRepeatTimeout,
  2. nsecs_tkeyRepeatDelay,nsecs_t*nextWakeupTime){
  3. ......
  4. //Readytostartanewevent.
  5. //Ifwedon'talreadyhaveapendingevent,gograbone.
  6. if(!mPendingEvent){
  7. if(mInboundQueue.isEmpty()){
  8. ......
  9. }else{
  10. //Inboundqueuehasatleastoneentry.
  11. EventEntry*entry=mInboundQueue.headSentinel.next;
  12. ......
  13. mInboundQueue.dequeue(entry);
  14. mPendingEvent=entry;
  15. }
  16. ......
  17. }
  18. ......
  19. switch(mPendingEvent->type){
  20. ......
  21. caseEventEntry::TYPE_KEY:{
  22. KeyEntry*typedEntry=static_cast<KeyEntry*>(mPendingEvent);
  23. ......
  24. done=dispatchKeyLocked(currentTime,typedEntry,keyRepeatTimeout,
  25. &dropReason,nextWakeupTime);
  26. break;
  27. }
  28. ......
  29. }
  30. ......
  31. }

我们忽略了这个函数的次要逻辑,主要关注键盘事件的主要处理流程。首先,如果前面发生的键盘事件都已经处理完毕,那么这里的mPendingEvent就为NULL,又因为前面我们把刚刚发生的键盘事件加入了mInboundQueue队列,因此,这里mInboundQueue不为NULL,于是,这里就把mInboundQueue队列中的键盘事件取出来,放在mPendingEvent变量中:

  1. mInboundQueue.dequeue(entry);
  2. mPendingEvent=entry;

由于这里发生的是键盘事件,即mPendingEvent->type的值为EventEntry::TYPE_KEY,于是,在接下来的switch语句中就会执行dispatchKeyLocked函数来分发键盘消息。

Step 12.InputDispatcher.dispatchKeyLocked

这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:

  1. boolInputDispatcher::dispatchKeyLocked(
  2. nsecs_tcurrentTime,KeyEntry*entry,nsecs_tkeyRepeatTimeout,
  3. DropReason*dropReason,nsecs_t*nextWakeupTime){
  4. ......
  5. //Identifytargets.
  6. if(!mCurrentInputTargetsValid){
  7. int32_tinjectionResult=findFocusedWindowTargetsLocked(currentTime,
  8. entry,nextWakeupTime);
  9. ......
  10. }
  11. //Dispatchthekey.
  12. dispatchEventToCurrentInputTargetsLocked(currentTime,entry,false);
  13. returntrue;
  14. }

InputDispatcher类中的mCurrentInputTargetsValid成员变量表示InputDispatcher是否已经标志出谁是当前激活的Activity窗口,如果没有,就需要通过findFocusedWindowTargetsLocked函数来把它找出来。当把当前激活的Activity窗口找出来以后,接下来就调用dispatchEventToCurrentInputTargetsLocked函数把键盘事件分发给它了。

我们先来看一InputDispatcher是如何找到当前激活的Activity窗口的,然后再分析它把键盘事件分发给当前激活Activity窗口的过程。

Step 13.InputDispatcher.findFocusedWindowTargetsLocked

这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:

  1. int32_tInputDispatcher::findFocusedWindowTargetsLocked(nsecs_tcurrentTime,
  2. constEventEntry*entry,nsecs_t*nextWakeupTime){
  3. mCurrentInputTargets.clear();
  4. int32_tinjectionResult;
  5. //Ifthereisnocurrentlyfocusedwindowandnofocusedapplication
  6. //thendroptheevent.
  7. if(!mFocusedWindow){
  8. if(mFocusedApplication){
  9. ......
  10. injectionResult=handleTargetsNotReadyLocked(currentTime,entry,
  11. mFocusedApplication,NULL,nextWakeupTime);
  12. gotoUnresponsive;
  13. }
  14. ......
  15. injectionResult=INPUT_EVENT_INJECTION_FAILED;
  16. gotoFailed;
  17. }
  18. //Checkpermissions.
  19. if(!checkInjectionPermission(mFocusedWindow,entry->injectionState)){
  20. injectionResult=INPUT_EVENT_INJECTION_PERMISSION_DENIED;
  21. gotoFailed;
  22. }
  23. //Ifthecurrentlyfocusedwindowispausedthenkeepwaiting.
  24. if(mFocusedWindow->paused){
  25. ......
  26. injectionResult=handleTargetsNotReadyLocked(currentTime,entry,
  27. mFocusedApplication,mFocusedWindow,nextWakeupTime);
  28. gotoUnresponsive;
  29. }
  30. //Ifthecurrentlyfocusedwindowisstillworkingonpreviouseventsthenkeepwaiting.
  31. if(!isWindowFinishedWithPreviousInputLocked(mFocusedWindow)){
  32. ......
  33. injectionResult=handleTargetsNotReadyLocked(currentTime,entry,
  34. mFocusedApplication,mFocusedWindow,nextWakeupTime);
  35. gotoUnresponsive;
  36. }
  37. //Success!Outputtargets.
  38. injectionResult=INPUT_EVENT_INJECTION_SUCCEEDED;
  39. addWindowTargetLocked(mFocusedWindow,InputTarget::FLAG_FOREGROUND,BitSet32(0));
  40. ......
  41. returninjectionResult;
  42. }

回忆前面我们分析应用程序注册键盘消息接收通道的过程时,在Step 9中,当前处于激活状态的应用程序会通过调用InputDispatcher类setInputWindows函数把把当前获得焦点的Activity窗口设置到mFocusedWindow中去,因此,这里的mFocusedWindow不为NULL,于是,就通过了第一个if语句的检查。

第二个if语句检查权限问题,原来,这个键盘事件除了是由硬件触发的外,也可以由其它进程注入进来的,如果这个键盘事件是由其它进程注入进来的,那么entry->injectState就不为NULL,它里面包含了事件注册者的进程ID和用户ID,于是,这里就会调用checkInjectionPermission来检查这个事件注入者的进程ID和用户ID,看看它是否具有这个权限。这里我们不考虑这种情况,因此,这里的entry->injectState为NULL,于是,这个if语句的检查也通过了。

第三个if语句检查当前激活的Activity窗口是否是处于paused状态,如果是的话,也不用进一步处理了。一般情况下,当前激活的Activity窗口都是处于resumed状态的,于是,这个if语句的检查也通过了。

第四个if语句检查当前激活的Activity窗口是否还正在处理前一个键盘事件,如果是的话,那就要等待它处理完前一个键盘事件后再来处理新的键盘事件了。这里我们也假设当前激活的Activity窗口不是正在处理前面的键盘事件,因此,这个if语句的检查也通过了。

最后,就调用addWindowTargetLocked函数把当前激活的Activity窗口添加到InputDispatcher类的mCurrentInputTargets成员变量中去。

Step 14.InputDispatcher.addWindowTargetLocked

这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:

  1. voidInputDispatcher::addWindowTargetLocked(constInputWindow*window,int32_ttargetFlags,
  2. BitSet32pointerIds){
  3. mCurrentInputTargets.push();
  4. InputTarget&target=mCurrentInputTargets.editTop();
  5. target.inputChannel=window->inputChannel;
  6. target.flags=targetFlags;
  7. target.xOffset=-window->frameLeft;
  8. target.yOffset=-window->frameTop;
  9. target.pointerIds=pointerIds;
  10. }

这个函数简单,就是把传进来的参数window添加到mCurrentInputTargets中去就完事了,后面InputDispatcher就会从mCurrentInputTargets中取出恰当的Activity窗口,然后把键盘事件分发给它。

回到Step 12中的dispatchKeyLocked函数,它接下来就调用dispatchEventToCurrentInputTargetsLocked来进一步处理了。

Step 15.InputDispatcher.dispatchEventToCurrentInputTargetsLocked

这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:

  1. voidInputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_tcurrentTime,
  2. EventEntry*eventEntry,boolresumeWithAppendedMotionSample){
  3. ......
  4. for(size_ti=0;i<mCurrentInputTargets.size();i++){
  5. constInputTarget&inputTarget=mCurrentInputTargets.itemAt(i);
  6. ssize_tconnectionIndex=getConnectionIndexLocked(inputTarget.inputChannel);
  7. if(connectionIndex>=0){
  8. sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
  9. prepareDispatchCycleLocked(currentTime,connection,eventEntry,&inputTarget,
  10. resumeWithAppendedMotionSample);
  11. }else{
  12. ......
  13. }
  14. }

这个函数的实现也比较简单,前面我们已经把当前需要接受键盘事件的Activity窗口添加到mCurrentInputTargets中去了,因此,这里就分别把它们取出来,然后调用prepareDispatchCycleLocked函数把键盘事件分发给它们处理。

前面我们在分析应用程序注册键盘消息接收通道的过程时,在Step 18中(InputDispatcher.registerInputChannel),把Server端的InputChannel封装成了一个Connection,然后以这个InputChannel中的Receive Pipe Fd作为键值把这个Connection对象保存在mConnectionsByReceiveFd中。这里,既然我们已经通过mCurrentInputTargets得到了表示当前需要接收键盘事件的Activity窗口的InputTarget对象,而且这个InputTarget对象的inputChannel就表示当初在InputDispatcher中注册的Server端InputChannel,因此,这里就可以把这个Connection对象取出来,最后调用prepareDispatchCycleLocked函数来进一步处理。

更多相关文章

  1. Android Apk反编译函数对应法则
  2. Android Edittext输入框点击空白处,软键盘消失
  3. Android 软键盘的显示与隐藏
  4. Android 的一些实用的函数
  5. Android事件分发机制——ViewRootImpl篇(前传)
  6. Android onTouchEvent事件
  7. 修改软键盘的回车键为发送键

随机推荐

  1. 从零编写一个一键生成mvp的android studi
  2. 我的Android学习之旅[1]——Android的系
  3. android ios 在浏览器中自定义URL
  4. Android中Dalvik和Art的认识和区别
  5. 在Windows上运行Android(安卓)4.0 的 CTS
  6. Android图形类库简要学习
  7. Android(安卓)动画分析之翻转效果
  8. Android(安卓)Looper用法及原理
  9. Android中ContentProvider的实现及定义自
  10. Android(安卓)ContentResolver使用说明