view的点击事件是从 WMS 传递过来,那么必须注册监听器之类到 WMS 中,
1、ViemRootImpl 中 addView 时可以看到注册了一个类似监听器的一个类,
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout,
mInputChannel);
}
这里主要是 new 了一个 InputChannel,然后通过 mWindowSession.addToDisplay 注册到 WMS 中。
2、mWindowSession.addToDisplay 逻辑可以追踪到,mWindowSesison 指向的是 com.android.server.wm.Session
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
}
mService 指向的就是 WMS, addWindow 的实现如下
public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
......
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
win.openInputChannel(outInputChannel);
}
......
}
openInputChanel 的实现如下
// WindowState.java
void openInputChannel(InputChannel outInputChannel) {
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
}
String name = getName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
mInputChannel = inputChannels[0];
mClientChannel = inputChannels[1];
mInputWindowHandle.inputChannel = inputChannels[0];
if (outInputChannel != null) {
mClientChannel.transferTo(outInputChannel);
mClientChannel.dispose();
mClientChannel = null;
} else {
// If the window died visible, we setup a dummy input channel, so that taps
// can still detected by input monitor channel, and we can relaunch the app.
// Create dummy event receiver that simply reports all events as handled.
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
}
mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
}
最后的 registerInputChannel 会执行到 natvie 方法。
现在注册流程已经很清楚了,那什么时候被被回调呢?,这个时候就需要去看 InputChanel 的实现了。
2、点击事件回调
// ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
......
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
.....
}
其中 WindowInputEventReceiver 的父类为 InputEventReceiver,其中有如下:
// InputEventReceiver.java
// Called from native code.
@SuppressWarnings("unused")
private void dispatchInputEvent(int seq, InputEvent event, int displayId) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event, displayId);
}
当点击事件 来之后, natvie 层通过回调 dispachInputEvent 方法,后续会执行到下面代码
// ViewRootImpl.java
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
.......
if (processImmediately) { // 这里为true
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
......
}
void doProcessInputEvents() {
......
deliverInputEvent(q);
......
}
deliverInputEvent 后面后调用到 ViewPostImeInputStage#process
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {
return processKeyEvent(q);
} else {
final int source = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
return processPointerEvent(q);
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
return processTrackballEvent(q);
} else {
return processGenericMotionEvent(q);
}
}
}
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
mAttachInfo.mHandlingPointerEvent = true;
//这里就是熟悉的 view 事件分发入口啦
boolean handled = mView.dispatchPointerEvent(event);
return handled ? FINISH_HANDLED : FORWARD;
}