Step 11. InputDispatcher.dispatchOnceInnerLocked

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

  1. void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout,
  2. nsecs_t keyRepeatDelay, nsecs_t* nextWakeupTime) {
  3. ......
  4. // Ready to start a new event.
  5. // If we don't already have a pending event, go grab one.
  6. if (! mPendingEvent) {
  7. if (mInboundQueue.isEmpty()) {
  8. ......
  9. } else {
  10. // Inbound queue has at least one entry.
  11. EventEntry* entry = mInboundQueue.headSentinel.next;
  12. ......
  13. mInboundQueue.dequeue(entry);
  14. mPendingEvent = entry;
  15. }
  16. ......
  17. }
  18. ......
  19. switch (mPendingEvent->type) {
  20. ......
  21. case EventEntry::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. bool InputDispatcher::dispatchKeyLocked(
  2. nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
  3. DropReason* dropReason, nsecs_t* nextWakeupTime) {
  4. ......
  5. // Identify targets.
  6. if (! mCurrentInputTargetsValid) {
  7. int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
  8. entry, nextWakeupTime);
  9. ......
  10. }
  11. // Dispatch the key.
  12. dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
  13. return true;
  14. }

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

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

Step 13. InputDispatcher.findFocusedWindowTargetsLocked

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

  1. int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
  2. const EventEntry* entry, nsecs_t* nextWakeupTime) {
  3. mCurrentInputTargets.clear();
  4. int32_t injectionResult;
  5. // If there is no currently focused window and no focused application
  6. // then drop the event.
  7. if (! mFocusedWindow) {
  8. if (mFocusedApplication) {
  9. ......
  10. injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
  11. mFocusedApplication, NULL, nextWakeupTime);
  12. goto Unresponsive;
  13. }
  14. ......
  15. injectionResult = INPUT_EVENT_INJECTION_FAILED;
  16. goto Failed;
  17. }
  18. // Check permissions.
  19. if (! checkInjectionPermission(mFocusedWindow, entry->injectionState)) {
  20. injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
  21. goto Failed;
  22. }
  23. // If the currently focused window is paused then keep waiting.
  24. if (mFocusedWindow->paused) {
  25. ......
  26. injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
  27. mFocusedApplication, mFocusedWindow, nextWakeupTime);
  28. goto Unresponsive;
  29. }
  30. // If the currently focused window is still working on previous events then keep waiting.
  31. if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindow)) {
  32. ......
  33. injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
  34. mFocusedApplication, mFocusedWindow, nextWakeupTime);
  35. goto Unresponsive;
  36. }
  37. // Success!  Output targets.
  38. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
  39. addWindowTargetLocked(mFocusedWindow, InputTarget::FLAG_FOREGROUND, BitSet32(0));
  40. ......
  41. return injectionResult;
  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. void InputDispatcher::addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
  2. BitSet32 pointerIds) {
  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. void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,
  2. EventEntry* eventEntry, bool resumeWithAppendedMotionSample) {
  3. ......
  4. for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
  5. const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);
  6. ssize_t connectionIndex = 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函数来进一步处理。

转载于:https://blog.51cto.com/shyluo/966635

Android应用程序键盘(Keyboard)消息处理机制分析(17)相关推荐

  1. Android系统中的Binder通信机制分析(7)- Java 层的 Binder 机制

    声明 其实对于Android系统Binder通信的机制早就有分析的想法,记得2019年6.7月份Mr.Deng离职期间约定一起对其进行研究的,但因为我个人问题没能实施这个计划,留下些许遗憾- 文中参考 ...

  2. Android应用程序键盘(Keyboard)消息处理机制分析(3)

    Step 15. Looper.pollOnce 这个函数定义在frameworks/base/libs/utils/Looper.cpp文件中,具体可以参考前面Android应用程序消息处理机制(L ...

  3. Android应用程序键盘(Keyboard)消息处理机制分析(12)

    Step 12. InputChannel.openInputChannelPair 这个函数定义在frameworks/base/core/java/android/view/InputChanne ...

  4. Android应用程序线程消息循环模型分析(5)

      从AsyncTask的实现可以看出,当我们第一次创建一个AsyncTask对象时,首先会执行下面静态初始化代码创建一个线程池sExecutor: private static final Bloc ...

  5. Android应用程序线程消息循环模型分析

    出自:http://blog.csdn.net/luoshengyang/article/details/6905587 我们知道,Android应用程序是通过消息来驱动的,即在应用程序的主线程(UI ...

  6. 以下未发布-Android的多线程以及异步消息处理机制,android移动开发基础案例教程源码

    1.Message: Message 是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间进行数据交换.除了 what 字段,还可以使用 arg1 和 arg2 来携带整型数据,使用 ...

  7. Android应用程序键盘(Keyboard)消息处理机制分析(20)

    Step 24. InputQueue.dispatchKeyEvent 这个函数定义在frameworks/base/core/java/android/view/InputQueue.java文件 ...

  8. Android应用程序键盘(Keyboard)消息处理机制分析(26)

    Step 7. LocalWindowManager.removeViewImmediate 这个函数定义在frameworks/base/core/java/android/view/Window. ...

  9. Android应用程序键盘(Keyboard)消息处理机制分析(14)

    3. InputManager分发键盘消息给应用程序的过程分析 在分析InputManager分发键盘消息给应用程序的过程之前,我们先假设现在没有键盘事件发生,因此,InputManager中的Inp ...

最新文章

  1. java数组中最小的k个元素_java – 在数组中找到k个最小整数
  2. 雷达图(python)
  3. OTN交换amp;P-OTN有效减少100G网络成本(一)
  4. C/C++中 static 的作用
  5. linux网口驱动实现(待续)
  6. Microsoft 推出在AzureApp Service上支持Windows容器的公开预览版
  7. Java工作笔记-IntelliJ IDEA中高效文件切换跳转
  8. 4,GIL全局解释器锁,event事件,信号量
  9. 【Vegas原创】Can't connect to X11 window server using ':0.0' 解决方法
  10. springMvc整合hibernate出现问题
  11. 文件上传功能如何测试
  12. java虚拟机学习笔记(五)---运行时的数据区域
  13. oracle数据库行转列(含例子表结构及查询sql)
  14. 【软件分析/静态程序分析学习笔记】1.静态程序分析(Static Program Analysis)介绍
  15. QQ连连看6.0 逆向分析
  16. 音乐铃声解析提取API接口
  17. 基于autojs7的皮皮虾极速版辅助
  18. oracle调用web severs,Oracle调用C#开发web services
  19. IOS学习六:Date Picker, Picker View选取器控件初步
  20. android 桌面快捷方式,Android应用开发之(如何自动在桌面创建快捷方式)

热门文章

  1. HashMap底层原理分析(put、get方法)
  2. 【题解】 bzoj2748 [HAOI2012]音量调节 (动态规划)
  3. 通用型硬件只是个传说
  4. 使用Physics_Body_Editor获得json文件的类
  5. Oracle EBS Color 色彩设置
  6. iphone编译时的注意事项
  7. Deep Reinforcement Learning 深度增强学习资源
  8. linux stat函数讲解
  9. 使用Nginx+FFMPEG搭建HLS直播转码服务器
  10. 跟我一起学docker(四)--容器的基本操作