android事件处理,InputDispatch怎么处理事件的?(4)
四,InputDispatch怎么处理事件的?
InputDispatch的循环同样是通过InputDispatchThread的ThreadLoop调用dispatchOnce实现的。
在分发事件的处理中,如果事件类型是TYPE_KEY,将分发给dispatchKeyLocked。
InputDispatcher.cpp
voidInputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
caseEventEntry:
done= dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
}
这个函数很长,只列出核心的部分。
boolInputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason*dropReason, nsecs_t* nextWakeupTime) {
在分发给具体的窗口之前,有些前期处理,比如:
按键的重复次数
entry->repeatCount= mKeyRepeatState.lastKeyEntry->repeatCount + 1;
//处理策略要我们稍后再试一次的情况
if(entry->interceptKeyResult ==
KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER){
if(currentTime < entry→interceptKeyWakeupTime)
if(entry->interceptKeyWakeupTime < *nextWakeupTime)
……
entry->interceptKeyResult= KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
}
//在事件分发出去前,给系统策略一个拦截的机会,可能系统需要对某些按键做前期处理。
if(entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
CommandEntry*commandEntry = postCommandLocked(
&InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
}
//也可能要放弃这个事件
if(*dropReason != DROP_REASON_NOT_DROPPED)
//重要的还是找到事件的接收方,然后投递给目标
Vector
int32_t injectionResult =findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets,nextWakeupTime);
//添加窗口到 inputTargets。
addMonitoringTargetsLocked(inputTargets);
//投递事件给inputTargets
dispatchEventLocked(currentTime,entry, inputTargets);
}
下面重点看下如何找到投递目标的,对于按键事件,就是找到当前的焦点窗口,也是最前端的。
int32_tInputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
constEventEntry* entry, Vector
//如果没有焦点应用,也没有焦点窗口,就drop掉这个事件,如果没有焦点窗口,但是有焦点应用,说明应用可能在启动的过程中,会等待一段时间,再试。
if(mFocusedWindowHandle == NULL) {
if (mFocusedApplicationHandle != NULL) {
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
mFocusedApplicationHandle,NULL, nextWakeupTime,
“Waiting because nowindow has focus but there is a “
“focused applicationthat may eventually add a window “
“when it finishesstarting up.”);
goto Unresponsive;
}
ALOGI(“Dropping event because there is no focused window or focusedapplication.”);
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
}
//走到这里,说明找到了焦点窗口:mFocusedWindowHandle,下面是权限检查。
if(! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
goto Failed;
}
//检查窗口是不是正在处理别的事件。
reason = checkWindowReadyForMoreInputLocked(currentTime,
mFocusedWindowHandle, entry, “focused”);
if(!reason.isEmpty()) {
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
mFocusedApplicationHandle,mFocusedWindowHandle, nextWakeupTime, reason.string());
goto Unresponsive;
}
//把窗口信息添加到InputTarget中。
addWindowTargetLocked(mFocusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,
BitSet32(0), inputTargets);
}
inputdispatch是怎么知道当前窗口mFocusedWindowHandle 的句柄的呢?通过跟踪是inputMonitor来设置的,最开始我们说InputManagerservice的启动时,提到InputManager设置了一个回调,其中的参数wm.getInputMonitor()就是InputMonitor,这个InputMonitor一方面实现了InputManagerService.WindowManagerCallbacks这个接口,另一方面为windowmanagerservice访问InputDispatch提供了接口,比如提供当前焦点窗口给InputDispatch,就是通过InputMonitor的函数updateInputWindowsLw。
下面看下设置当前焦点窗口给InputDispatch的过程:
当窗口有变化时,WindowManagerService会调用InputMonitor的方法:updateInputWindowsLw。
void removeWindowLocked(WindowState win)@WindowManagerService.java{
mInputMonitor.updateInputWindowsLw(true/*force*/);
}
public void updateInputWindowsLw(booleanforce)@InputMonitor.java{
//这里的参数 mInputWindowHandles是个数组,输入窗口句柄的集合。
// mService是WindowManagerService,
//mInputManager 是InputManagerService,这个对象是在WindowManagerService的构造函数中初始化的。
mService.mInputManager.setInputWindows(mInputWindowHandles);
}
往下就到了InputManagerService这边。
public voidsetInputWindows(InputWindowHandle[] windowHandles)
@InputManagerService.java{
//通过jni由java层转到cpp层。
nativeSetInputWindows(mPtr,windowHandles);
}
static void nativeSetInputWindows(JNIEnv*env, jclass /* clazz */,
jlong ptr, jobjectArray windowHandleObjArray)
@com_android_server_input_InputManagerService.cpp{
NativeInputManager* im =reinterpret_cast
im->setInputWindows(env, windowHandleObjArray);
}
最后把包含窗口句柄的数组传到了InputDispatch。
voidNativeInputManager::setInputWindows(JNIEnv* env, jobjectArraywindowHandleObjArray) {
mInputManager->getDispatcher()->setInputWindows(windowHandles);
}
这里会确定当前的焦点窗口,并赋值给mFocusedWindowHandle。
void InputDispatcher::setInputWindows(constVector
if (windowHandle->getInfo()->hasFocus) {
newFocusedWindowHandle = windowHandle;
}
mFocusedWindowHandle= newFocusedWindowHandle;
}
还没有评论,来说两句吧...