Android输入系统笔记

来源:互联网 发布:淘宝店铺如何上传图片 编辑:程序博客网 时间:2024/06/10 17:31
InputDispatcher的线程循环由InputDispatchr::diapatchOnce()完成


InputDispatcher::diapatchOnce(){
1、通过dispatcherInnerOnceLocked()进行输入事件的派发,其传出参数nextWeakupTime决定下次派发线程的循还执行时间
2、执行命令队列中的命令,可以通过InputDispatcher::postCommandLocked()函数将命令追加到命令列表中
3,如果有必要,将派发线程进入休眠状态,并由nextWeakupTime确定具体的休眠时间,Looper的pollOnce的实质就是epoll_wait()
  派发线程在三种情况下将被唤醒:
1、有事件注入派发列队时,调用Looper::wake()主动唤醒
2、epol_wait()坚挺的fd有epoll_event发生时
3、到达nextWeakupTime的时间点时
}




//该函数体现了派发过程的整体流程
InputDispatcher::dispatcherInnerOnceLocked(nextWeakUpTime){
1、setInputDispatchMode()函数可以使InputDispatcher在禁用,冻结,和正常三种状态下切换
2、从派发队列中取出一事件进行派发
如果派发队列为空,则直接返回。nextWeakupTime保持LONG_LONG_MAX,派发队列进入无限的休眠期
   resetANRTimeoutsLocked(),为事件重置ANR信息
3、检查时间是否需要被丢弃,dropReason描述了时间是否需要被丢弃
4、执行dispatchMotionLocked()进行Motion事件的派发
}


DropReason枚举完整的描述了是事件被丢弃的所有原因:
1、DROP_REASON_POLICY:
2、DROP_REASON_APP_SWITCH
3、DROP_REASON_BLOCKED
4、DROP_REASON_DISABLED
5、DROP_REASON_STALE


//专门为Motion事件寻找合适的目标窗口
dispatchMotionLocked(){
1、根据Motion事件,寻找合适的窗口,injectionResult保存寻找结果,找到的合适的窗口将会被保存在inputTarget列表中
findTouchedWindowTargetsLocked(correntTime,entry,inputTargets,nextWakeupTime,&conflictPointerActions)
2、调用dispatchEventLocked()将事件派发给inputTargets中
}


InputDispatcher::findTouchedWindowTargetsLocked(){
1、遍历mWindowsHandles列表中所有的WindowHandle,检查事件坐标点是否落在其上
2、检查TempTouchState中所有的目标窗口是否已准备好接受新的输入事件
3、若窗口查找成功,设置injectionResult为SUCCEEDED,并将生成的InputTarget放入参数inputTargets中
}


InputDispatcher::dispatchEventLocked(){
//根据InputTarget中的InputChannel获取对应的Connection对象的索引
1、getConnectionIndexLocked(inputTarget,inputChannel)
//调用prepareDispatchCycleLocked()针对当前的InputTarget启动发送事件循环
}




prepareDispatchCycleLocked(){
//将事件添加到Connection的发送队列中
 enqueueDiapatchEntriesLocked(curentTime,connection,eventEntry,inputTarget)
}


enqueueDiapatchEntriesLocked(curentTime,connection,eventEntry,inputTarget){
//将事件信息封装成DispatchEntry,然后注入Connection的发送队列中
enqueueDiapatchEntryLocked(connection,eventEntry,inputTarget,InputTarget::FLAG_DISPATCH_AS_IS)

//启动发送循环
startDispatchCycleLocked(currentTime,connection)
}
FLAG_DISPATCH_AS_IS表示不修改事件的action类型
startDispatchCycleLocked(currentTime,connection){
//不断的从发送队列中获取DispatchEntry,并将事件发送到InputChannel中

//根据不同的事件类型,选择InputPublisher不同的发送函数

//将DispatchEntry转存到waitQueue中
}

//派发按键事件
dispatchKeyLocked(){

}


//将事件注入派发列队
InputDispatcher::notifyKey(){
1、根据policyF了该修改事件的mateState
2、询问按键事件上的派发策略
interceptKeyBeforeQueueing()
3、构建KeyEntry
}




Command命令执行doInterceptKeyBeforeDispatcher()函数想DispatcherPolicy查询派发策略,将结果保存在interceptKeyResult中
InputDispatcher::doInterceptKeyBeforeDispatcher(){
//创建KeyEvent对象
//调用interceptKeyBeforeDiapatching()从DispatcherPolicy中获取派发策略,返回延迟派发的时间delay
}


delay的三种取值:
1、INTERCEPT_KEY_RESULT_SKIP:表示DispatcherPolicy自己处理按键事件,不希望派发给用户
2、INTERCEPT_KEY_RESULT_CONTINUE:表示可以正常的派发给用户
3、INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER:表示DispatcherPolicy尚未决定好如何处理这个按键事件,暂停派发工作,时间又delay决定



DispatcherPolicy是一个实现了DispatcherPolicyInterface的对象,保存在InputDispatcher的mPolicy成员变量中


interceptMotionBeforeQueueing()的调用发生在Reader线程中,其主要作用是返回policyFlags派发策略,PhoneWindowManager可以根据设备的状态返回如下策略:
POLICY_FLAG_WOKE_HERE:
POLICY_FLAG_BRIGHT_HERE
POLICY_FLAG_PASS_TO_USER

InputManagerService::InputManagerService.filterInputEvent(InputEvent event,int policyFlags){

}




输入事件的发送,接收与反馈
InputChannel的本质是一对SocketPair(非网络套接字),用来实现在本机内进行进程的通信
InputChannel::openInputChannelPair(){

}


public int addWindow(......,InputChannel outInputChannel){
//openInputChannelPair()调用Native层的openInputChannelPair()函数,并将两个Native层的InputChannel对象封装为Java对象返回


//其中一个InputChannel端交给WindowState保存
1、win.setInputChannel(inputChannels[0])

//另一个InputChannel则通过transferTo函数传递给调用者
 2、inputChannels[1].transferTo(outInputChannel)

//将WindowState所保存的InputChannel向IMS进行注册
 3、registerInputChannel(win.mInputChannel,win.mInputWindowHandle)


//将所有的窗口信息更新到InputManagerService
 mInputMonitor.updateInputWindowsLw(false)
}


registerInputChannel(InputChannel inputChannel,INputWindowHandle inputWindowHandle){
//直接调用nativeRegisterInputChannel,由Native层完成注册工作
 nativeRegisterInputChannel(mPtr,inputChannel,inputWindowHandle,false)
}


实际的注册过程在InputDispatcher的同名函数完成
InputChannel(const sp<InputChannel>& inputChannel,const sp<InputWindowHandle>& inputWindowHandle,bool monitor){
1、为传入的InputChannel创建一个Connection对象并进行封装
new Connection(inpputChannel,inputWindowHandle,monitor)

2、监听InputChannel的可读性。Looper对象具有监听文件描述符可读性时间的能力
}




InputMonitor.updateInputWindowsLw(boolean force){
//获取用于遍历所有WMS窗口的枚举器,其参数表示采用反向遍历
//将窗口的布局信息转存到inputWindowHandle中,然后将inputWindowHandle保存到mInputWindowHandles列表中
 addInputWindowHandleLw();
 
//mInputWindowHandles列表提交给InputManagerService
 mServic.mInputManager.setInputWindows(mInputWindowHandles)
 
//清空mInputWindowHandles列表
 clearInputWindowHandleLw()
}


setInputWindows(mInputWindowHandles){
1使用传入的InputWindowHandle列表替换现有的列表

2、调用updateInfo()函数,将JAVA层的布局信息搬运到其InputWindowInfo

3、将焦点窗口保存到mInputWindowHandle中
}




窗口端连接的建立
窗口端通过addWindow()函数获得InputChannel后,便会使用它创建一个InputEventReceiver对象,该对象可以接收来自InputChannel的输入事件
InputHandler是SampleWindow实现的一个继承自InputEventReceiver的类


事件的接收
InputPublisher将事件以InputMessage的形式写入InputChannel之后,Looper会被唤醒,执行InputEventReceiver的handle-Event(),该方法直
接调用了consumeEvent()。
consumeEvent(){
1、通过consume()函数从InputChannel中读取一条InputMessage,解析为InputEvent,作为参数传出

2、根据事件的类型分别创建KeyEvent与MotionEvent的Java对象

3、通过JNI回调Java层的InputEventReceiver的dispatchInputEvent()函数
}


InputEventReceiver.dispatchInputEvent(){
//保存来自InputDispatcher的序列号

//调用onInputEvent(event)函数
}


事件的反馈与发送循环
事件的反馈由InputEventReceiver.finishInputEvent()发起
InputEventReceiver.finishInputEvent(){
//从字典中将事件对应的序列号取出
IndexOfKey();
//由nativeFinishInputEvent完成反馈动作
nativeFinishInputEvent(mReceiverPtr,seq,handled)
}


发送过程由NativeInputEventReceiver完成
NativeInputEventReceiver::finishInputEvent(){
//由mInputConsumer将handle两个信息以InputMessage的形式写入InputChannel中
mInputConsumer.sendFinishedSignal(seq,handled)
}


当InputChannel被写入数据时,会触发服务端的InputChannel可读性事件,InputDispatcher的被唤醒,执行handleReceiverCallback()
handleReceiverCallback(){
//1、获取对应的Connection对象

//2、循环读取竟可能多的反馈信息

//3、调用finishDispatchCycleLocked()函数完成对反馈的处理
}




finishDispatchCycleLocked()函数将向InputDispatcher发送一个命令,处理反馈的函数是doDispatcherCycleFinishLockedInterruptible()
doDispatcherCycleFinishLockedInterruptible(){

}




焦点窗口:即当前操作的窗口,寻找焦点窗口的基本原则是沿着ZOrder的顺序从上到下遍历窗口







原创粉丝点击