Android事件拦截(3)——系统拦截和应用拦截

本文主要分析触摸事件和按键事件在不同阶段被拦截的流程,总结在不同阶段不同方法中返回值的含义。

按键的拦截

(1)interceptKeyBeforeQueueing

interceptKeyBeforeQueueing方法的意义就是在事件入队列前拦截按键事件,也就是如果这个阶段被拦截,事件将不会再被分发。

在分发keyevent事件前,会先将event上报给PhoneWindownManager处理,如果PhoneWindowManager消费掉,则不会继续分发给应用,流程如下:
Android事件拦截(3)——系统拦截和应用拦截_第1张图片
调用栈如下:

InputDispatcher::injectInputEvent // 触发调用1
InputDispatcher::notifyKey // 触发调用2
    com_android_server_input_InputManagerService::NativeInputManager::interceptKeyBeforeQueueing
        InputManagerService::interceptKeyBeforeQueueing
            IMS::InputManagerCallback::interceptKeyBeforeQueueing
                WMS::PhoneWindowManager::interceptKeyBeforeQueueing
  • InputDispatcher.notifyKey会通过JNI的方式向PhoneWindowManager通报事件,先交由PhoneWindowManager来处理一些系统的按键,如果PhoneWindowManager已经处理消费且认为按键事件不应再分发给应用程序,则会返回0,否则返回1(ACTION_PASS_TO_USER);

我们在日常开发中,有时候希望事件在系统中消费掉,不传递给应用进行处理,那么可以在这个阶段添加我们的逻辑,只需要将PhoneWindowManager.interceptKeyBeforeQueueing返回0即可。

(2)interceptKeyBeforeDispatching

interceptKeyBeforeDispatching是在事件分发前进行拦截,同样也是交给PhoneWindomManager来进行处理,流程如下:
Android事件拦截(3)——系统拦截和应用拦截_第2张图片
调用栈如下:

InputDispatcher::dispatchOnce
    InputDispatcher::dispatchOnceInnerLocked
        //InputDispatcher::mPolicy // mPolicy:: com_android_server_input_InputManagerService.cpp
        InputDispatcher::dispatchKeyLocked
            InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible
                com_android_server_input_InputManagerService::NativeInputManager::interceptKeyBeforeDispatching
                // jni InputManagerService::nativeInit中初始化
                	InputManagerService::interceptKeyBeforeDispatching
            			IMS::InputManagerCallback::interceptKeyBeforeDispatching
                			WMS::PhoneWindowManager::interceptKeyBeforeDispatching
  • InputDisptcher调用dispatchKeyLocked来处理InputReader发送过来的事件,此时的KeyEntry.interceptKeyResult为INTERCEPT_KEY_RESULT_UNKNOWN,如果此事件在上一阶段被设置为POLICY_FLAG_PASS_TO_USER,那么就会生成一个command,去交给PhoneWindowManager去处理;
  • PhoneWindowManager调用interceptKeyBeforeDispatching来处理一些特殊的key事件,如power、home等,然后返回事件被处理的时机(延时),如果事件应被拦截,则返回-1,立即分发则返回0,延迟分发则返回延时的时间;
  • InputDispatcher在处理command的时候根据PhoneWindowManager处理的返回值,将KeyEntry.interceptKeyResult置为不同的flag;
  • 由于InputDispatcher loop里每次只处理一个事件,而每次循环都会优先处理堆积的command,而且mPendingEvent只有当事件被处理完才会置null,因此在下一次loop的时候,处理完command就立即继续处理这个key事件,根据interceptKeyResult来选择是否拦截;

前面两个阶段都是框架层Framework将事件拦截,下面的dispatchKeyEvent主要讲的是应用所能修改的,按照调用的逻辑层次来分析。
Android事件拦截(3)——系统拦截和应用拦截_第3张图片

  • 调用View.dispatchKeyEvent(mView就是DecorView),当Window没有被destory,走Activity.dispatchKeyEvent -> PhoneWindow.superDispatchKeyEvent -> DecorView.superDispatchKeyEvent -> ViewGroup.dispatchKeyEvent -> View.dispatchKeyEvent。此调用链中,Activity.dispatchKeyEvent、View.dispatchKeyEvent都是应用开发常常override的方法;
  • 在Activity.dispatchKeyEvent方法(默认实现)中,当PhoneWindow.superDispatchKeyEvent返回了false值,则走KeyEvent.dispatch方法,然后回调Activity的onKeyDown/onKeyUp等方法;
  • 如果Activity.dispatchKeyEvent方法返回了false,则调用到PhoneWindow的onKeyDown/onKeyUp方法;

(3)KeyEvent的拦截总结

Android事件拦截(3)——系统拦截和应用拦截_第4张图片

触摸事件的拦截

(1)dispatchTouchEvent

在ViewRootImpl阶段,拦截的过程如下:
Android事件拦截(3)——系统拦截和应用拦截_第5张图片

  • InputDispatch将事件分发给对应的ViewRootImpl中,继而将事件分发给DecorView,然后调用到Activity.dispatchTouchEvent -> ViewGroup.dispatchTouchEvent -> View.dispatchTouchEvent。当有一个流程返回true,则将事件拦截;
  • 当Activity.dispatchTouchEvent返回false没有拦截事件,则会调用Activity.onTouchEvent来处理;

(2)MotionEvent的拦截总结

Android事件拦截(3)——系统拦截和应用拦截_第6张图片
想了解通俗易懂的应用事件分发机制,可参考如下文章:Android事件拦截(二)——通俗易懂事件分发机制。

你可能感兴趣的:(Android系统源码分析,事件拦截)