android事件处理,把事件通知到焦点窗口,(5)

五,接下来的问题是InputDispatch是怎么把事件通知到到焦点窗口InputTarget的呢?

先看下InputTarget的定义,

InputDispatcher.h

一个inputtarget表明了怎样把一个输入事件分发给一个特定的窗口。

struct InputTarget {

       enum{

              //这个flag指示 事件应该发给前台应用程序。

              FLAG_FOREGROUND= 1 << 0,

//这个flag表明,这个motionevent,通常是触摸事件,落在了一个被上面的可见窗口遮盖的区域中了,

              FLAG_WINDOW_IS_OBSCURED= 1 << 1,

       };

//重点是这个inputChannel,一个inputchannel包含了一个本地的unix domain socket,它用于进程之间发送和接收输入消息,

       sp<InputChannel>inputChannel;

}

由此可以知道,InputDispatch跟应用程序通信就是通过这个inputChannel了,既然这样, 每添加一个应用窗口,都要创建一个这样的inputChannel的通道,所以从应用窗口的添加看起:

在一个应用程序第一次启动的时候,肯定要先执行一次View树的遍历,然后再向WindowManagerService申请窗口注册,为什么不是先申请注册窗口,在执行viewtree的遍历呢?以为窗口一旦注册好就意味着可以接收事件、分发事件了,所以在这之前Viewtree要做好接收事件的准备。

ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParamsattrs, View panelParentView){

//这里执行Viewtree的遍历,

       requestLayout();

//这里开始申请注册窗口。

       mInputChannel= new InputChannel();

       res= mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,

              getHostVisibility(),mDisplay.getDisplayId(),

              mAttachInfo.mContentInsets,mAttachInfo.mStableInsets,

              mAttachInfo.mOutsets,mInputChannel);

}

通过Session把请求发到WindowManagerService,只关注InputChannel的创建。

WindowManagerService.java

public int addWindow(Session session,IWindow client, int seq,

           WindowManager.LayoutParams attrs, int viewVisibility, int displayId,

           Rect outContentInsets, Rect outStableInsets, Rect outOutsets,

           InputChannel outInputChannel){

       win.openInputChannel(outInputChannel);

}

WindowState.java

void openInputChannel(InputChanneloutInputChannel) {

//经过jni调用,就到了通道的本地实现,下面有这个通道详细的本地实现。

       String name = makeInputChannelName();

       InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);

 

       mInputChannel= inputChannels[0];

       mClientChannel= inputChannels[1];

       mInputWindowHandle.inputChannel= inputChannels[0];

//将 mClientChannel客户端的所有权转给了outInputChannel,这个 outInputChannel就是应用程序申请窗口时创建的。

       mClientChannel.transferTo(outInputChannel);

//注册一个输入通道input channel并将其关联到输入窗口mInputWindowHandle,把它作为输入事件的target, mInputChannel和 mInputWindowHandle都是被inputdispatcher使用的,下面会分析这个注册的详细代码。

       mService.mInputManager.registerInputChannel(mInputChannel,mInputWindowHandle);  

}

下面是通道的本地实现,通过socketpare的方式,创建了sockets,一个通道有一个服务端,一个客户端,在这个场景中,服务端提供给InputDispatch-发出事件,客户端提供给应用的输入队列-消费事件,

InputTransport.cpp

status_tInputChannel::openInputChannelPair(const String8& name,

       sp<InputChannel>& outServerChannel,sp<InputChannel>& outClientChannel) {

   int sockets[2];

   socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)    

   int bufferSize = SOCKET_BUFFER_SIZE;

   setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize,sizeof(bufferSize));

   setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize,sizeof(bufferSize));

   setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize,sizeof(bufferSize));

   setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize,sizeof(bufferSize));

 

   String8 serverChannelName = name;

   serverChannelName.append(" (server)");

   outServerChannel = new InputChannel(serverChannelName, sockets[0]);

 

   String8 clientChannelName = name;

   clientChannelName.append(" (client)");

   outClientChannel = new InputChannel(clientChannelName, sockets[1]);

   return OK;

}

看下那个注册的详细实现,这个关系到inputDispatch怎么利用通道发布事件。

mService.mInputManager.registerInputChannel(mInputChannel,mInputWindowHandle);

这里的 mInputManager是InputManagerService,所以就到了:

InputManagerService.java

public voidregisterInputChannel(InputChannel inputChannel,     

       InputWindowHandleinputWindowHandle) {

      nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle,false);

}

最终还是native层来实现的。

com_android_server_input_InputManagerService.cpp

static voidnativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,

       jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj,jboolean monitor) {

//这里调用了InputDispatch(cpp)的registerInputChannel。

       status_t status = im->registerInputChannel(

             env, inputChannel,inputWindowHandle, monitor);

}

InputDispatcher.cpp

status_tInputDispatcher::registerInputChannel(const sp<InputChannel>&inputChannel,

       const sp<InputWindowHandle>& inputWindowHandle, bool monitor){

//这里创建了 Connection,在它的构造函数中会实例化inputPublisher,并传参 inputChannel,其中InputDispatch会通过inputPublisher这个对象发布事件给inputChannel,

       sp<Connection>connection = new Connection( inputChannel, inputWindowHandle, monitor);

}

InputTransport.cpp

InputPublisher把 inputChannel赋值给 mChannel,后面会通过这个 mChannel对象sendMessage。

InputPublisher::InputPublisher(const sp<InputChannel>&channel) :

       mChannel(channel) {

}

把这些理清后,再回头看InputDispatch的事件分发就好明白了。

InputDispatcher.cpp

voidInputDispatcher::dispatchEventLocked(nsecs_t currentTime,

       EventEntry* eventEntry, const Vector<InputTarget>&inputTargets) {

       prepareDispatchCycleLocked(currentTime,connection, eventEntry, &inputTarget);

}

voidInputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,

       const sp<Connection>& connection, EventEntry* eventEntry,const InputTarget* inputTarget) {

       enqueueDispatchEntriesLocked(currentTime,connection,

              splitMotionEntry,inputTarget);

}

voidInputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,

       const sp<Connection>& connection, EventEntry* eventEntry,const InputTarget* inputTarget) {

//把eventEntry转成dispatchEntry,并入队到

       enqueueDispatchEntryLocked(connection,eventEntry, inputTarget,

           InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);

//把队列的中事件分发出去,调用的是InputPublisher的publishKeyEvent函数。  

       startDispatchCycleLocked(currentTime,connection);

}

InputDispatcher.cpp

status_tInputPublisher::publishKeyEvent(       uint32_t seq,        int32_tdeviceId,        int32_t

       source,        int32_t action,        int32_t flags,        int32_t keyCode,        int32_t scanCode,       

       int32_tmetaState,        int32_trepeatCount,        nsecs_tdownTime,        nsecs_t eventTime) {

   InputMessage msg;

//看到了应用程序中keycode,keyAction等。

   msg.header.type = InputMessage::TYPE_KEY;

   msg.body.key.seq = seq;

   msg.body.key.deviceId = deviceId;

    msg.body.key.source = source;

   msg.body.key.action = action;

   msg.body.key.flags = flags;

   msg.body.key.keyCode = keyCode;

   msg.body.key.scanCode = scanCode;

   msg.body.key.metaState = metaState;

   msg.body.key.repeatCount = repeatCount;

   msg.body.key.downTime = downTime;

   msg.body.key.eventTime = eventTime;

//把inputmessage发送通道的服务端。

   return mChannel->sendMessage(&msg);

}

到这里事件的发送就完了,接下来就是对事件的接收处理。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值