在第二篇文章介绍了事件通过 connection->inputPublisher.publishMotionEvent 就可以发送到我们app的窗口,那么具体是如何分发的呢?
以activity为例,我们打开一个activity就会创建一个PhoneWindow,setContentView会调用PhoneWindow的setContentView,PhoneWindow持有DecorView,DecorView是整个页面的根容器,我们传入的页面会被添加到其中的id为content的子容器中。可以参考我其他的文章Activity显示原理,本篇重点不在这块。
public void setContentView(View view, ViewGroup.LayoutParams params) {
getWindow().setContentView(view, params);
}
而页面的显示是在onResume之后开始的。
ActivityThread.java
final void handleResumeActivity(...){
//这里会调用Activity的onResume方法
r = performResumeActivity(token, clearHide, reason);
//页面的DecorView
View decor = r.window.getDecorView();
ViewManager wm = a.getWindowManager();
//这里调用了WindowManagerImpl的addView方法把整个页面view添加进去了
wm.addView(decor, l);
}
WindowManagerImpl.java
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
//调用WindowManagerGlobal的addView
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
ViewRootImpl root;
View panelParentView = null;
root = new ViewRootImpl(view.getContext(), display);
mViews.add(view);
root.setView(view, wparams, panelParentView);
}
WindowManagerGlobal是一个单例,所有页面的添加最终都是委托它来完成的。它会为每一个页面创建一个ViewRootImpl实例,然后调用ViewRootImpl的setView方法,这个方法很重要,继续分析。
ViewRootImpl.java
public void setView(View view,...) {
synchronized (this) {
if (mView == null) {
mView = view;
mAdded = true;
int res;
//1 这里很重要,但是本篇不用关心它
requestLayout();
//创建了一个InputChannel(重点)
mInputChannel = new InputChannel();
try {
//2 可以看到mInputChannel也被传进去了
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
}
}
}
InputChannel是一个输入通道,通过它可以读取到IMS发过来的信息。但是目前创建的InputChannel还是一个空的对象,也就是mPtr还没有被赋值,现在有个印象就好。
InputChannel.java
public final class InputChannel implements Parcelable {
private long mPtr; // used by native code
}
紧接着调用了mWindowSession.addToDispla方法,但是mWindowSession是什么呢?
ViewRootImpl.java
final IWindowSession mWindowSession;
public ViewRootImpl(Context context, Display display) {
//mWindowSession是在ViewRootImpl创建时赋值的
mWindowSession = WindowManagerGlobal.getWindowSession();
}
WindowManagerGlobal.java
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
//获取服务端WindowManagerService在客户端的代理
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(...);
} catch (RemoteException e) {
}
}
return sWindowSession;
}
}
通过windowManager跨进程调用到WMS的openSession方法。
WindowManagerService.java
public IWindowSession openSession(...) {
Session session = new Session(this, callback, client, inputContext);
return session;
}
直接创建了一个Session然后返回了,这个Session也是用来跨进程通信的。
接着前面的分析知道了mWindowSession怎么来的,那么mWindowSession.addToDisplay会走到:
Session.java
public int addToDisplay(...) {
//mService就是WindowManagerService
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}
就这样通过mWindowSession就成功的跨进程调用到WindowManagerService的addWindow方法。
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) {
synchronized(mWindowMap) {
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
//重点1
win.openInputChannel(outInputChannel);
mWindowMap.put(client.asBinder(), win);
//重点2
mInputMonitor.updateInputWindowsLw(false /*force*/);
}
return res;
}
接着调用了WindowState的openInputChannel方法,把客户端传过来的InputChannel传进去了 。
WindowState.java
void openInputChannel(InputChannel outInputChannel) {
String name = getName();
//1、打开了一对通道
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
mInputChannel = inputChannels[0];
mClientChannel = inputChannels[1];
mInputWindowHandle.inputChannel = inputChannels[0];
if (outInputChannel != null) {
mClientChannel.transferTo(outInputChannel);
mClientChannel = null;
}
mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
}
先来分析注释1,调用InputChannel.openInputChannelPair方法返回了一对InputChannel啥意思呢?
InputChannel.java
public static InputChannel[] openInputChannelPair(String name) {
return nativeOpenInputChannelPair(name);
}
private static native InputChannel[] nativeOpenInputChannelPair(String name);
nativeOpenInputChannelPair是一个native方法,追进去看看。
android_view_InputChannel.cpp
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
String8 name(nameChars);
env->ReleaseStringUTFChars(nameObj, nameChars);
sp<InputChannel> serverChannel;
sp<InputChannel> clientChannel;
//创建native层服务断和客户端InputChannel,里面使用的是socket
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
//创建java层的InputChannel[]数组
jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
//创建两个java层的InputChannel,并把native层的InputChannel传进去
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
std::make_unique<NativeInputChannel>(serverChannel));
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
std::make_unique<NativeInputChannel>(clientChannel));
//把两个java层的InputChannel设置到InputChannel[]数组,然后返回它
env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
return channelPair;
}
再来贴下之前的代码
WindowState.java
void openInputChannel(InputChannel outInputChannel) {
String name = getName();
//1、获取到InputChannel[]数组
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
mInputChannel = inputChannels[0];
mClientChannel = inputChannels[1];
mInputWindowHandle.inputChannel = inputChannels[0];
if (outInputChannel != null) {
mClientChannel.transferTo(outInputChannel);
mClientChannel = null;
}
mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
}
根据前面的分析知道, InputChannel.openInputChannelPair(name)返回了 InputChannel[]数组,其中inputChannels[0]代表服务断,inputChannels[1]代表客户端。然后调用了 mClientChannel.transferTo(outInputChannel)方法。
InputChannel.java
public void transferTo(InputChannel outParameter) {
//注意参数,outParameter是之前客户端传过来的那个空的InputChannel
nativeTransferTo(outParameter);
}
private native void nativeTransferTo(InputChannel other);
android_view_InputChannel.cpp
static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
jobject otherObj) {
//取出在服务端创建的客户端InputChannel持有的NativeInputChannel指针赋值给在客户端创建的指针
NativeInputChannel* nativeInputChannel =
android_view_InputChannel_getNativeInputChannel(env, obj);
//把NativeInputChannel指针赋值给在客户端创建的InputChannel的mPtr字段
android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
//服务断这边的InputChannel没用了,其mPtr字段置空
android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
}
其实很简单,就是把之前在客户端那边创建的InputChnannel的mPtr字段赋值,之前是空的,现在mPtr指向了一个native层的NativeInputChannel对象。
到现在大体能明白一些了,客户端的InputChnannel和服务端的InputChnannel分别持有一个NativeInputChannel,NativeInputChannel是通信的本质,分别代表了socket的一端,如果服务端往socket一端发送数据,客户端就能够在另一端获取到。
WindowState.java
void openInputChannel(InputChannel outInputChannel) {
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;
}
//接着调用InputManagerService的registerInputChannel注册InputChannel,
mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
}
mInputWindowHandle就是窗口的信息,不可能把view注册到WindowManagerService中,view也不支持跨进程传输,因此客户端的每个窗口都会在服务端有对应的InputWindowHandle,代表着窗口的信息。
InputManagerService.java
public void registerInputChannel(InputChannel inputChannel,
InputWindowHandle inputWindowHandle) {
nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}
private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel,
InputWindowHandle inputWindowHandle, boolean monitor);
注册的目的是让InputChannel和具体的窗口关联起来,这样当有输入事件到来,系统会找到具体的窗口,然后就可以找到对应的InputChannel,知道怎么把事件发送出去。
com_android_server_input_InputManagerService.cpp
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
//获取服务端的InputChannel
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
//获取InputWindowHandle对应的NativeInputWindowHandle
sp<InputWindowHandle> inputWindowHandle =
android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
//调用NativeInputManager进行注册
status_t status = im->registerInputChannel(
env, inputChannel, inputWindowHandle, monitor);
}
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
//调用InputDispatcher的registerInputChannel注册
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, inputWindowHandle, monitor);
}
InputDispatcher.cpp
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
//创建一个Connection
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
int fd = inputChannel->getFd();
//把Connection添加到mConnectionsByFd
mConnectionsByFd.add(fd, connection);
return OK;
}
InputDispatcher.cpp
InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
inputPublisher(inputChannel),... {
}
把connection添加到mConnectionsByFd是为了输入事件分发的时候可以找到Connection对象。而Connection的inputPublisher持有了InputChannel,拿到了InputChannel然后就可以往通道的一端发送数据,另一端就可以获取到数据了。还记得第二遍文章分析输入事件的分发有这段代码吗?回顾下
InputDispatcher.cpp#
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
pokeUserActivityLocked(eventEntry);
for (size_t i = 0; i < inputTargets.size(); i++) {
//遍历所有的窗口目标
const InputTarget& inputTarget = inputTargets.itemAt(i);
//获取连接索引
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
//Connection可以理解为InputDispatcher和目标窗口的连接,是用来跨进程通信的
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
//开始事件分发循环,事件最终会被分发到目标窗口
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
} else {
}
}
}
//最终通过下面的代码发送输入事件
status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
motionEntry->deviceId, motionEntry->source,
dispatchEntry->resolvedAction, motionEntry->actionButton,
dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
motionEntry->metaState, motionEntry->buttonState,
xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount, motionEntry->pointerProperties,
usingCoords);
分析完如何注册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) {
synchronized(mWindowMap) {
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
//重点1
win.openInputChannel(outInputChannel);
mWindowMap.put(client.asBinder(), win);
//重点2
mInputMonitor.updateInputWindowsLw(false /*force*/);
}
return res;
}
InputMonitor.java
/* Updates the cached window information provided to the input dispatcher. */
void updateInputWindowsLw(boolean force) {
final InputWindowHandle dragWindowHandle = mService.mTaskPositioner.mDragWindowHandle;
if (dragWindowHandle != null) {
//把InputWindowHandle添加到mInputWindowHandles
addInputWindowHandle(dragWindowHandle);
}
// Add all windows on the default display.
mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
}
UpdateInputForAllWindowsConsumer#
private void updateInputWindows(boolean inDrag) {
// 更新所有的窗口信息
mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle);
}
把窗口的信息添加到mInputWindowHandles,接着又调用updateInputWindows去更新所有的窗口信息,比如我们添加了一个新的窗口(启动新页面)或者原来的窗口大小发生变化都需要去更新所有的窗口信息。接着调用到InputManagerService的setInputWindows方法。
InputManagerService.java
public void setInputWindows(InputWindowHandle[] windowHandles,
InputWindowHandle focusedWindowHandle) {
nativeSetInputWindows(mPtr, windowHandles);
}
又走到native层了。
com_android_server_input_InputManagerService.cpp
static void nativeSetInputWindows(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobjectArray windowHandleObjArray) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
im->setInputWindows(env, windowHandleObjArray);
}
NativeInputManager#
void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
Vector<sp<InputWindowHandle> > windowHandles;
if (windowHandleObjArray) {
jsize length = env->GetArrayLength(windowHandleObjArray);
for (jsize i = 0; i < length; i++) {
jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
sp<InputWindowHandle> windowHandle =
android_server_InputWindowHandle_getHandle(env, windowHandleObj);
if (windowHandle != NULL) {
windowHandles.push(windowHandle);
}
env->DeleteLocalRef(windowHandleObj);
}
}
//更新InputDispatcher中的窗口信息
mInputManager->getDispatcher()->setInputWindows(windowHandles);
}
继续分析InputDispatcher.cpp的setInputWindows方法。
InputDispatcher.cpp
void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;
mWindowHandles = inputWindowHandles;
}
每次窗口信息发生变,都会区更新mWindowHandles这个集合,该集合就代表了客户端的所有的窗口信息,当输入事件到来,就会去遍历这个窗口信息集合,去判断窗口是否是可以触摸的,事件的坐标是否落在这个窗口上。通过这种方式就可以找到合适的窗口去处理事件,有了窗口信息,然后就可以拿到与之关联的InputChannel,然后通过InputChannel往通道的一端发送事件,那么客户端最终又是如何接收并且处理这些事件的呢?还记得前面的ViewRootImpl的setView方法中创建的InputChannel吗,线索肯定在那里!
ViewRootImpl.java
public void setView(View view,...) {
synchronized (this) {
if (mView == null) {
mView = view;
//创建了一个InputChannel(重点)
mInputChannel = new InputChannel();
try {
//2 做一些InputChannel和窗口信息的注册,并且会把上面的InputChannel的mPtr赋值
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
if (mInputChannel != null) {
//创建窗口输入事件的接收者
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
}
}
}
我们的窗口具体是如何接收事件的,核心就在WindowInputEventReceiver里面了。我有点想吐!先让我吐会吧。
可以看到创建窗口的输入者会把InputChannel传进去。
ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
@Override
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}
}
当收到事件最终会调用到onInputEvent,然后会把事件分发给具体的DecorView。不过我们先看 super(inputChannel, looper)这行。
public abstract class InputEventReceiver {
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
//又是native方法,并且把inputChannel和MessageQueue传进去了
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);
}
}
继续跟进android_view_InputEventReceiver.cpp中的nativeInit方法
android_view_InputEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
//创建native层的NativeInputEventReceiver对象,然后调用它的初始化方法
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
status_t status = receiver->initialize();
return reinterpret_cast<jlong>(receiver.get());
}
status_t NativeInputEventReceiver::initialize() {
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}
void NativeInputEventReceiver::setFdEvents(int events) {
if (mFdEvents != events) {
mFdEvents = events;
//拿到通道的fd句柄
int fd = mInputConsumer.getChannel()->getFd();
if (events) {
//调用Looper的addFd,注意第四个参数是回调的意思
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}
继续追踪Looper的addFd方法
Looper.cpp
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
{
//回调
request.callback = callback;
request.data = data;
if (requestIndex < 0) {
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
}
} // release lock
return 1;
}
解释下这段代码的意思,通过epoll去监听这个通道的fd。如果发现有事件,也就是服务端对应的通道另一端有数据发送。最终会调用回调的handleEvent方法。
Looper.cpp
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
result = pollInner(timeoutMillis);
}
int Looper::pollInner(int timeoutMillis) {
// Invoke all response callbacks.
for (size_t i = 0; i < mResponses.size(); i++) {
Response& response = mResponses.editItemAt(i);
if (response.request.ident == POLL_CALLBACK) {
//就是这里调用了回调的handleEvent方法
int callbackResult = response.request.callback->handleEvent(fd, events, data);
}
}
return result;
}
接着NativeInputEventReceiver的handleEvent方法。
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
return 1;
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
//...
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
}
接着又调用到java层
InputEventReceiver.java
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
然后就调用到了onInputEvent方法,onInputEvent方法会走到InputEventReceiver子类的
ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
//就是走到这里
@Override
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}
}
ViewRootImpl.java
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
if (processImmediately) {
//进入这个分支
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
}
ViewRootImpl.java
void doProcessInputEvents() {
// Deliver all pending input events in the queue.
while (mPendingInputEventHead != null) {
deliverInputEvent(q);
}
}
ViewRootImpl.java
private void deliverInputEvent(QueuedInputEvent q) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
q.mEvent.getSequenceNumber());
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStage stage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
//然后走这里
stage.deliver(q);
} else {
finishInputEvent(q);
}
}
ViewRootImpl.java#InputStage
public final void deliver(QueuedInputEvent q) {
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
forward(q);
} else if (shouldDropInputEvent(q)) {
finish(q, false);
} else {
//然后走到onProcess注意是走到它的实现类
apply(q, onProcess(q));
}
}
ViewRootImpl.java#ViewPostImeInputStage
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {
//key事件
return processKeyEvent(q);
} else {
final int source = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
//ponit事件走这里
return processPointerEvent(q);
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
return processTrackballEvent(q);
} else {
return processGenericMotionEvent(q);
}
}
}
ViewRootImpl.java#ViewPostImeInputStage
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
//接着走View的dispatchPointerEvent
boolean handled = mView.dispatchPointerEvent(event);
return handled ? FINISH_HANDLED : FORWARD;
}
View.java
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
//走这里
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
调用dispatchTouchEvent会走到DecorView的dispatchTouchEvent方法
DecorView.java
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
会先调用cb的dispatchTouchEvent方法,而这个cb是什么呢?
Activity.java
final void attach(...) {
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setCallback(this);
}
原来就是Activity,所有会走到Activity的dispatchTouchEvent方法了。接着就开始了事件的分发流程了。可以参考另一篇文章Android——事件分发机制源码分析