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

四,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<InputTarget> 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<InputTarget>& 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<NativeInputManager*>(ptr);

 

   im->setInputWindows(env, windowHandleObjArray);

}

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

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

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

}

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

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

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

           newFocusedWindowHandle = windowHandle;

      }    

       mFocusedWindowHandle= newFocusedWindowHandle;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值