在InputReader从EventHub中获取输入事件,包含触摸屏事件、物理按键事件等,然后转交给InputDispatcher线程,InputDispatcher经过筛选,过滤输入事件。对于触摸事件通过调用findTouchedWindowTargetsLocked()函数找到合适的InputTarget,然后通过dispatchEventLocked()->prepareDispatchCycleLocked()->enqueueDispatchEntriesLocked()->enqueueDispatchEntryLocked()->connection->outboundQueue.enqueueAtTail(dispatchEntry)添加到与InputTarget一一对应的connection中的一个队列中。如果之前该队列无数据,并且当前触摸事件已成功加入该队列,则继续调用startDispatchCycleLocked()函数进行分发处理。在startDispatchCycleLocked()中,有一个while循环,该循环从connection->outboundQueue队列中取出输入事件,如果该输入事件是按键(key)事件,则调用connection->inputPublisher.publishKeyEvent()函数,如果是触摸事件则调用connection->inputPublisher.publishMotionEvent()。publishKeyEvent()和publishMotionEvent()都是调用mChannel->sendMessage()将输入事件发送出去。mChannel是一个C++层InputChannel对象,该对象的赋值过程如下:registerInputChannel()->newConnection->Connection()构造函数->InputPublisher()构造函数。事实上,在registerInputChannel()被调用之前,ViewRootImple在增加一个窗口时调用ViewRootImpl.setView()->mWindowSession.addToDisplay()-WindowManagerService.addWindow(),在addWindow()中会创建一对InputChannel(Nativie层),实际上是创建一对Socket,服务端InputChanel被WMS注册到InputDispatcher中,客户端InputChannel被返回给ViewRootImpl,ViewRootImpl将客户端InputChannel作为参数new一个InputEventReceiver对象,在InputEventReceiver()构造函数中继续调用nativeInit()函数来创建一个native层的NativeInputEventReceiver对象,前面创建的客户端InputChannel会保存在该对象中。

总结:WMS会调用native层接口创建一对套接字,服务端保存在InputDispatcher中,客户端保存在NativeInputEventReceiver中(android_view_inputEventReceiver.cpp)。

很容易想到输入事件是从InputDispatcher流向NativeInputEventReceiver中。在创建一个native层的NativeInputEventReceiver对象后会立即调用NativeInputEventReceiver->initialize(),该函数调用mMessageQueue->getLooper()->addFd(fd,0, events, this, NULL)将客户端socket句柄添加到Looper的轮询队列中,参数this指向NativeInputEventReceiver本身,意味着只要服务端InputDispatcher发送输入事件,客户端收到这个事件,就调用NativeInputEventReceiver的某个函数,具体调用哪个函数,自然是NativeInputEventReceiver实现了LooperCallback的接口函数handleEvent()。但此时收到的事件只是代表socket客户端有事件来,并没有把具体的事件读取出来,这点需要注意。

总结:客户端收到输入事件,即调用NativeInputEventReceiver->handleEvent()函数。

在handleEvent()函数中,继续调用consumeEvents()->mInputConsumer.consume()->mChannel->receiveMessage(&mMsg)将具体输入事件读取出来,然后调用env->CallVoidMethod(receiverObj.get(),gInputEventReceiverClassInfo.dispatchInputEvent,seq, inputEventObj),可以知道native层读取输入事件后,然后会回调java层InputEventReceiver.java中的dispatchInputEvent()函数。事实上,

dispatchInputEvent继续调用onInputEvent(event);此时可能并不调用InputEventReceiver类中的onInputEvent()方法,而是调用子类onInputEvent()方法。在ViewRootImpl中存在WindowInputEventReceiver类型变量mInputEventReceiver,WindowInputEventReceiver类继承InputEventReceiver,并实现onInputEvent()方法由此可得出结论:native层socket客户端读取输入事件,最终调用InputEventReceiver类子类的onInputEvent()方法,ViewRootImpl继承InputEventReceiver,因此ViewRootImpl.onInputEvent()将被调用。

总结:对于一般的触摸屏事件最终处理者是ViewRootImpl类,对于输入法则处理者是IInputMethodSessionWrapper类,当然WMS是不会处理这些输入事件的。

继续研究ViewRootImpl.onInputEvent()函数,onInputEvent()->doProcessInputEvents()->deliverInputEvent(),deliverInputEvent()函数中会调用stage.deliver(q),stage是mFirstPostImeInputStage 或 mFirstInputStage,这个两个InputStage对象在setView中赋值。InputStage类设计就是责任链模式。因为触摸事件是要分发到具体的View上来,所以对于一般的触摸事件最后是传递到ViewPostImeInputStage类中来处理,处理函数是processPointerEvent(q),这个函数调用mView.dispatchPointerEvent(event)将事件分发出去,mView具体是什么呢?mView其实就是DecorView,每一个窗口有且仅有一个DecorView,且处在最顶层,由于DecorView未重写dispatchPointerEvent(),所以调用还是父类View类的dispatchPointerEvent()方法。

[java] view plaincopy

publicfinalbooleandispatchPointerEvent(MotionEventevent){

if(event.isTouchEvent()){

returndispatchTouchEvent(event);

}else{

returndispatchGenericMotionEvent(event);

}

}

该方法继续调用dispatchTouchEvent(event),DecorView重新了该方法:

[java] view plaincopy

@Override

publicbooleandispatchTouchEvent(MotionEventev){

finalCallbackcb=getCallback();

returncb!=null&&!isDestroyed()&&mFeatureId<0?cb.dispatchTouchEvent(ev)

:super.dispatchTouchEvent(ev);

}

getCallback()函数获取apk注册的用于拦截按键、触摸等事件的回调函数。一般window不会拦截处理触摸事件,所以会继续调用super.dispatchTouchEvent(ev),即父类ViewGroup的dispatchTouchEvent()函数,在该函数中寻找到对应的View再继续调用dispatchTransformedTouchEvent()

[java] view plaincopy

for(inti=childrenCount-1;i>=0;i--){

finalintchildIndex=customOrder?

getChildDrawingOrder(childrenCount,i):i;

finalViewchild=children[childIndex];

if(!canViewReceivePointerEvents(child)

||!isTransformedTouchPointInView(x,y,child,null)){

continue;

}

newTouchTarget=getTouchTarget(child);

if(newTouchTarget!=null){

//Childisalreadyreceivingtouchwithinitsbounds.

//Giveitthenewpointerinadditiontotheonesitishandling.

newTouchTarget.pointerIdBits|=idBitsToAssign;

break;

}

resetCancelNextUpFlag(child);

if(dispatchTransformedTouchEvent(ev,false,child,idBitsToAssign)){

//Childwantstoreceivetouchwithinitsbounds.

mLastTouchDownTime=ev.getDownTime();

mLastTouchDownIndex=childIndex;

mLastTouchDownX=ev.getX();

mLastTouchDownY=ev.getY();

newTouchTarget=addTouchTarget(child,idBitsToAssign);

alreadyDispatchedToNewTouchTarget=true;

break;

}

具体的分发规则可自行研究代码。

ViewGroup.dispatchTouchEvent()函数分析

[html] view plaincopy

@Override

publicbooleandispatchTouchEvent(MotionEventev){

if(mInputEventConsistencyVerifier!=null){

mInputEventConsistencyVerifier.onTouchEvent(ev,1);

}

if(DBG_MOTION||DBG_TOUCH){

Xlog.d(TAG,"(ViewGroup)dispatchTouchEvent1:ev="+ev+",mFirstTouchTarget="

+mFirstTouchTarget+",this="+this);

}

booleanhandled=false;

if(onFilterTouchEventForSecurity(ev)){

finalintaction=ev.getAction();

finalintactionMasked=action&MotionEvent.ACTION_MASK;

//Handleaninitialdown.

if(actionMasked==MotionEvent.ACTION_DOWN){

//Throwawayallpreviousstatewhenstartinganewtouchgesture.

//Theframeworkmayhavedroppedtheuporcanceleventforthepreviousgesture

//duetoanappswitch,ANR,orsomeotherstatechange.

cancelAndClearTouchTargets(ev);

resetTouchState();

}

//Checkforinterception.

finalbooleanintercepted;

if(actionMasked==MotionEvent.ACTION_DOWN

||mFirstTouchTarget!=null){

finalbooleandisallowIntercept=(mGroupFlags&FLAG_DISALLOW_INTERCEPT)!=0;

if(!disallowIntercept){

intercepted=onInterceptTouchEvent(ev);

///M:addlogtohelpdebugging

if(intercepted==true){

if(DBG_TOUCH){

Xlog.d(TAG,"Toucheventwasinterceptedevent="+ev+",this="+this);

}

}

ev.setAction(action);//restoreactionincaseitwaschanged

}else{

intercepted=false;

}

}else{

//Therearenotouchtargetsandthisactionisnotaninitialdown

//sothisviewgroupcontinuestointercepttouches.

intercepted=true;

}

//Checkforcancelation.

finalbooleancanceled=resetCancelNextUpFlag(this)

||actionMasked==MotionEvent.ACTION_CANCEL;

//Updatelistoftouchtargetsforpointerdown,ifneeded.

finalbooleansplit=(mGroupFlags&FLAG_SPLIT_MOTION_EVENTS)!=0;

if(DBG_MOTION){

Xlog.d(TAG,"(ViewGroup)dispatchTouchEvent2:actionMasked="+actionMasked

+",intercepted="+intercepted+",canceled="+canceled+",split="

+split+",mChildrenCount="+mChildrenCount+",mFirstTouchTarget="

+mFirstTouchTarget+",this="+this);

}

TouchTargetnewTouchTarget=null;

booleanalreadyDispatchedToNewTouchTarget=false;

if(!canceled&&!intercepted){

if(actionMasked==MotionEvent.ACTION_DOWN

||(split&&actionMasked==MotionEvent.ACTION_POINTER_DOWN)

||actionMasked==MotionEvent.ACTION_HOVER_MOVE){

finalintactionIndex=ev.getActionIndex();//always0fordown

finalintidBitsToAssign=split?1<<ev.getPointerId(actionIndex)

:TouchTarget.ALL_POINTER_IDS;

//Cleanupearliertouchtargetsforthispointeridincasethey

//havebecomeoutofsync.

removePointersFromTouchTargets(idBitsToAssign);

finalintchildrenCount=mChildrenCount;

if(newTouchTarget==null&&childrenCount!=0){

finalfloatx=ev.getX(actionIndex);

finalfloaty=ev.getY(actionIndex);

//Findachildthatcanreceivetheevent.

//Scanchildrenfromfronttoback.

finalView[]children=mChildren;

finalbooleancustomOrder=isChildrenDrawingOrderEnabled();

for(inti=childrenCount-1;i>=0;i--){

finalintchildIndex=customOrder?

getChildDrawingOrder(childrenCount,i):i;

finalViewchild=children[childIndex];

if(!canViewReceivePointerEvents(child)

||!isTransformedTouchPointInView(x,y,child,null)){

if(DBG_MOTION){

Xlog.d(TAG,"(ViewGroup)dispatchTouchEventcontinue6:i="

+i+",count="+childrenCount+",child="+child

+",this="+this);

}

continue;

}

newTouchTarget=getTouchTarget(child);

if(DBG_MOTION){

Xlog.d(TAG,"(ViewGroup)dispatchTouchEventtochild3:child="

+child+",childrenCount="+childrenCount+",i="+i

+",newTouchTarget="+newTouchTarget+",idBitsToAssign="

+idBitsToAssign+",mFirstTouchTarget="+mFirstTouchTarget

+",this="+this);

}

if(newTouchTarget!=null){

//Childisalreadyreceivingtouchwithinitsbounds.

//Giveitthenewpointerinadditiontotheonesitishandling.

newTouchTarget.pointerIdBits|=idBitsToAssign;

break;

}

resetCancelNextUpFlag(child);

if(dispatchTransformedTouchEvent(ev,false,child,idBitsToAssign)){

//Childwantstoreceivetouchwithinitsbounds.

mLastTouchDownTime=ev.getDownTime();

mLastTouchDownIndex=childIndex;

mLastTouchDownX=ev.getX();

mLastTouchDownY=ev.getY();

newTouchTarget=addTouchTarget(child,idBitsToAssign);

alreadyDispatchedToNewTouchTarget=true;

break;

}

}

}

if(newTouchTarget==null&&mFirstTouchTarget!=null){

//Didnotfindachildtoreceivetheevent.

//Assignthepointertotheleastrecentlyaddedtarget.

newTouchTarget=mFirstTouchTarget;

while(newTouchTarget.next!=null){

newTouchTarget=newTouchTarget.next;

}

newTouchTarget.pointerIdBits|=idBitsToAssign;

}

}

}

//Dispatchtotouchtargets.

if(mFirstTouchTarget==null){

//Notouchtargetssotreatthisasanordinaryview.

handled=dispatchTransformedTouchEvent(ev,canceled,null,

TouchTarget.ALL_POINTER_IDS);

}else{

//Dispatchtotouchtargets,excludingthenewtouchtargetifwealready

//dispatchedtoit.Canceltouchtargetsifnecessary.

TouchTargetpredecessor=null;

TouchTargettarget=mFirstTouchTarget;

while(target!=null){

finalTouchTargetnext=target.next;

if(alreadyDispatchedToNewTouchTarget&&target==newTouchTarget){

handled=true;

}else{

finalbooleancancelChild=resetCancelNextUpFlag(target.child)

||intercepted;

if(dispatchTransformedTouchEvent(ev,cancelChild,

target.child,target.pointerIdBits)){

handled=true;

}

if(DBG_MOTION){

Xlog.d(TAG,"dispatchTouchEventmiddle5:cancelChild="+cancelChild

+",mFirstTouchTarget="+mFirstTouchTarget+",target="

+target+",predecessor="+predecessor+",next="+next

+",this="+this);

}

if(cancelChild){

if(predecessor==null){

mFirstTouchTarget=next;

}else{

predecessor.next=next;

}

target.recycle();

target=next;

continue;

}

}

predecessor=target;

target=next;

}

}

//Updatelistoftouchtargetsforpointeruporcancel,ifneeded.

if(canceled

||actionMasked==MotionEvent.ACTION_UP

||actionMasked==MotionEvent.ACTION_HOVER_MOVE){

resetTouchState();

}elseif(split&&actionMasked==MotionEvent.ACTION_POINTER_UP){

finalintactionIndex=ev.getActionIndex();

finalintidBitsToRemove=1<<ev.getPointerId(actionIndex);

removePointersFromTouchTargets(idBitsToRemove);

}

}

if(DBG_MOTION){

Xlog.d(TAG,"(ViewGroup)dispatchTouchEventend4:handled="+handled+",mFirstTouchTarget="

+mFirstTouchTarget+",this="+this);

}

if(!handled&&mInputEventConsistencyVerifier!=null){

mInputEventConsistencyVerifier.onUnhandledEvent(ev,1);

}

returnhandled;

}