PhoneWindowManager处理事件分析[轉載https://blog.csdn.net/u012439416/article/details/546]
1, 基本概念
PhoneWindowManager也是运行于systemserver线程中,在Event事件分发之前处理,比如电源键。Event事件分发后,仅有包含Activity的apk线程才可以处理,如果apk中没有activity但是想处理Event事件怎么办呢?可以在PhoneWindowManager做做文章了。
在SystemServer中,
inputManager = new InputManagerService(context); wm = WindowManagerService.main(context, inputManager, mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL, !mFirstBoot, mOnlyCore); ServiceManager.addService(Context.WINDOW_SERVICE, wm); ServiceManager.addService(Context.INPUT_SERVICE, inputManager); mActivityManagerService.setWindowManager(wm); inputManager.setWindowManagerCallbacks(wm.getInputMonitor()); // 消息分发之前的回调 inputManager.start();
InputManagerService的创建以及启动已经论述了,在此就不多说了。在
WindowManagerService中新建了PhoneWindowManager和InputMonitor,并且将设置为InputManagerService对象的回调对象。其实这2个类都和Event的处理有关,在Event分发之前进行处理,相当于截取,具体的细节就一层一层抽丝剥茧了。
PhoneWindowManager是没有对应的C/C++层代码了。
看下InputManagerService的setWindowManagerCallbacks方法,
public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) { mWindowManagerCallbacks = callbacks; }
因此, InputManagerService的变量mWindowManagerCallbacks指向InputMonitor对象。
2处理流程
InputDispatcher的notifyKey方法中,Event进队列之前,会调用interceptKeyBeforeQueueing方法,
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
mPolicy变量是什么呢?通过查找,是NativeInputManager对象,
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) { bool interactive = mInteractive.load(); if (interactive) { policyFlags |= POLICY_FLAG_INTERACTIVE; } if ((policyFlags & POLICY_FLAG_TRUSTED)) { nsecs_t when = keyEvent->getEventTime(); JNIEnv* env = jniEnv(); jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent); jint wmActions; if (keyEventObj) { wmActions = env->CallIntMethod(mServiceObj, gServiceClassInfo.interceptKeyBeforeQueueing, keyEventObj, policyFlags); if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) { wmActions = 0; } android_view_KeyEvent_recycle(env, keyEventObj); env->DeleteLocalRef(keyEventObj); } ••• }
在register_android_server_InputManager方法中,
int res = jniRegisterNativeMethods(env, "com/android/server/input/InputManagerService", gInputManagerMethods, NELEM(gInputManagerMethods)); ••• GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeQueueing, clazz, "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;I)I");
很明显了,调用Java层InputManagerService的interceptKeyBeforeQueueing方法,后面就没有什么困难了,最后调用PhoneWindowManager的interceptKeyBeforeQueueing方法。
看下InputMonitor的方法,有一些也是同样的方法调用,关键是C/C++层的代码什么时候调用,觉得InputMonitor的主要目的还是解耦,防止PhoneWindowManager和InputManagerService太紧,
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { mService.mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen); } public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered) { mService.mPolicy.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered); } public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags); } public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) { return mService.mPolicy.interceptMotionBeforeQueueingNonInteractive( whenNanos, policyFlags); } public long interceptKeyBeforeDispatching( InputWindowHandle focus, KeyEvent event, int policyFlags) { WindowState windowState = focus != null ? (WindowState) focus.windowState : null; return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags); } public KeyEvent dispatchUnhandledKey( InputWindowHandle focus, KeyEvent event, int policyFlags) { WindowState windowState = focus != null ? (WindowState) focus.windowState : null; return mService.mPolicy.dispatchUnhandledKey(windowState, event, policyFlags); } public int getPointerLayer() { return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_POINTER) * WindowManagerService.TYPE_LAYER_MULTIPLIER + WindowManagerService.TYPE_LAYER_OFFSET; }
在InputDispatcher.cpp的中的Event入队列之后,dispatchKeyLocked方法中会调用doInterceptKeyBeforeDispatchingLockedInterruptible方法,然后调用NativeInputManager的interceptKeyBeforeDispatching方法,
nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, &event, entry->policyFlags);
最后会调用PhoneWindowManager的interceptKeyBeforeDispatching方法。
所以,如果apk中没有acitivity但是想监听Event事件怎么办呢?
在PhoneWindowManager的interceptKeyBeforeQueueing或者interceptKeyBeforeDispatching方法中稍加处理就可以了。