android事件处理,InputDispatch怎么处理事件的?(4)

朴灿烈づ我的快乐病毒、 2022-06-08 07:51 525阅读 0赞

四,InputDispatch怎么处理事件的?

InputDispatch的循环同样是通过InputDispatchThread的ThreadLoop调用dispatchOnce实现的。

在分发事件的处理中,如果事件类型是TYPE_KEY,将分发给dispatchKeyLocked。

InputDispatcher.cpp

voidInputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {

caseEventEntry::TYPE_KEY:

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 inputTargets;

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& inputTargets, nsecs_t*nextWakeupTime) {

//如果没有焦点应用,也没有焦点窗口,就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(ptr);

im->setInputWindows(env, windowHandleObjArray);

}

最后把包含窗口句柄的数组传到了InputDispatch。

voidNativeInputManager::setInputWindows(JNIEnv* env, jobjectArraywindowHandleObjArray) {

mInputManager->getDispatcher()->setInputWindows(windowHandles);

}

这里会确定当前的焦点窗口,并赋值给mFocusedWindowHandle。

void InputDispatcher::setInputWindows(constVector >& inputWindowHandles) @InputDispatcher.cpp{

if (windowHandle->getInfo()->hasFocus) {

newFocusedWindowHandle = windowHandle;

}

mFocusedWindowHandle= newFocusedWindowHandle;

}

发表评论

表情:
评论列表 (有 0 条评论,525人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Android事件处理

      UI编程通常都会伴随事件处理,Android也不例外,它提供了两种方式的事件处理:基于回调的事件处理和基于监听器的事件处理。 对于基于监听器的事件处理而言,主要