InputManagerService 输入事件是如何分发到view(四)

在第二篇文章介绍了事件通过 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——事件分发机制源码分析

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值