按键事件首先通过PhoneWindowManager的interceptKeyBeforeDispatching方法被拦截,然后分发到应用层,一些系统事件:HOME,MENU,SEARCH,会在这里做下预处理。那底层事件是如何传到interceptKeyBeforeDispatching方法中呢?
通过查看谁调用了此方法(eclipse中右键单击此方法名,选择open call hierarchy),发现InputMonitor.java调用了此方法:
public long interceptKeyBeforeDispatching(
InputWindowHandle focus, KeyEvent event, int policyFlags) {
WindowState windowState = focus != null ? (WindowState) focus.windowState : null;
return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags);
}
@SuppressWarnings("unused")
public long interceptKeyBeforeDispatching(InputWindowHandle focus,
KeyEvent event, int policyFlags) {
return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(
focus, event, policyFlags);
}
public InputManager(Context context, WindowManagerService windowManagerService) {
this.mContext = context;
this.mWindowManagerService = windowManagerService;
this.mCallbacks = new Callbacks();
Looper looper = windowManagerService.mH.getLooper();
Slog.i(TAG, "Initializing input manager");
nativeInit(mContext, mCallbacks, looper.getQueue());
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
}
那么如何找到C++层这个相对应的方法呢?其实很简单,我们看下InputManager.java的路径
\frameworks\base\services\java\com\android\server\wm
通常在和java(\frameworks\base\services\java)同目录下会有相对应的jni的目录结构(\frameworks\base\services\jni)
通过Source Insight 搜索对应目录(PS这样快)下的nativeInit字串,发现这样的一个数组:
static JNINativeMethod gInputManagerMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "(Landroid/content/Context;"
"Lcom/android/server/wm/InputManager$Callbacks;Landroid/os/MessageQueue;)V",
(void*) android_server_InputManager_nativeInit },
android_server_InputManager_nativeInit就是C++层相对应的方法,在com_android_server_InputManager.cpp中:
static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
jobject contextObj, jobject callbacksObj, jobject messageQueueObj) {
if (gNativeInputManager == NULL) {
sp looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
gNativeInputManager = new NativeInputManager(contextObj, callbacksObj, looper);
} else {
LOGE("Input manager already initialized.");
jniThrowRuntimeException(env, "Input manager already initialized.");
}
}
mInputManager = new InputManager(eventHub, this, this);
InputManager::InputManager(
const sp& eventHub,
const sp& readerPolicy,
const sp& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
InputDispatcher中的doInterceptKeyBeforeDispatchingLockedInterruptible函数调用了mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
&event, entry->policyFlags);传入事件,mPolicy就是上面代码中的dispatcherPolicy对象。
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
CommandEntry* commandEntry) {
KeyEntry* entry = commandEntry->keyEntry;
KeyEvent event;
initializeKeyEvent(&event, entry);
mLock.unlock();
nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
&event, entry->policyFlags);
mLock.lock();
if (delay < 0) {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
} else if (!delay) {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
} else {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
entry->interceptKeyWakeupTime = now() + delay;
}
entry->release();
}
对于c++层如何获得的linux设备的按键事件,以及如何通过InputDispatcher分发这些事件感兴趣的,可以查看frameworks\base\services\input下的代码,可以先从InputManager.cpp的构造函数入手,或者查看网上相关文章。这里暂时不描述了。
文章错误之处请指出,大家共同进步,转载请注明出处,谢谢!