在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()->new Connection->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
- public final boolean dispatchPointerEvent(MotionEvent event) { 
- if (event.isTouchEvent()) { 
- return dispatchTouchEvent(event); 
- } else { 
- return dispatchGenericMotionEvent(event); 
- } 
- } 
该方法继续调用dispatchTouchEvent(event),DecorView重新了该方法:
[java] view plaincopy
- @Override 
- public boolean dispatchTouchEvent(MotionEvent ev) { 
- final Callback cb = getCallback(); 
- return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) 
- : super.dispatchTouchEvent(ev); 
- } 
getCallback() 函数获取apk注册的用于拦截按键、触摸等事件的回调函数。一般window不会拦截处理触摸事件,所以会继续调用 super.dispatchTouchEvent(ev),即父类ViewGroup的dispatchTouchEvent()函数,在该函数中寻找 到对应的View再继续调用dispatchTransformedTouchEvent()
[java] view plaincopy
- for (int i = childrenCount - 1; i >= 0; i--) { 
- final int childIndex = customOrder ? 
- getChildDrawingOrder(childrenCount, i) : i; 
- final View child = children[childIndex]; 
- if (!canViewReceivePointerEvents(child) 
- || !isTransformedTouchPointInView(x, y, child, null)) { 
- continue; 
- } 
- newTouchTarget = getTouchTarget(child); 
- if (newTouchTarget != null) { 
- // Child is already receiving touch within its bounds. 
- // Give it the new pointer in addition to the ones it is handling. 
- newTouchTarget.pointerIdBits |= idBitsToAssign; 
- break; 
- } 
- resetCancelNextUpFlag(child); 
- if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { 
- // Child wants to receive touch within its bounds. 
- mLastTouchDownTime = ev.getDownTime(); 
- mLastTouchDownIndex = childIndex; 
- mLastTouchDownX = ev.getX(); 
- mLastTouchDownY = ev.getY(); 
- newTouchTarget = addTouchTarget(child, idBitsToAssign); 
- alreadyDispatchedToNewTouchTarget = true; 
- break; 
- } 
具体的分发规则可自行研究代码。
ViewGroup.dispatchTouchEvent()函数分析
[html] view plaincopy
- @Override 
- public boolean dispatchTouchEvent(MotionEvent ev) { 
- if (mInputEventConsistencyVerifier != null) { 
- mInputEventConsistencyVerifier.onTouchEvent(ev, 1); 
- } 
- if (DBG_MOTION || DBG_TOUCH) { 
- Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent 1: ev = " + ev + ",mFirstTouchTarget = " 
- + mFirstTouchTarget + ",this = " + this); 
- } 
- boolean handled = false; 
- if (onFilterTouchEventForSecurity(ev)) { 
- final int action = ev.getAction(); 
- final int actionMasked = action & MotionEvent.ACTION_MASK; 
- // Handle an initial down. 
- if (actionMasked == MotionEvent.ACTION_DOWN) { 
- // Throw away all previous state when starting a new touch gesture. 
- // The framework may have dropped the up or cancel event for the previous gesture 
- // due to an app switch, ANR, or some other state change. 
- cancelAndClearTouchTargets(ev); 
- resetTouchState(); 
- } 
- // Check for interception. 
- final boolean intercepted; 
- if (actionMasked == MotionEvent.ACTION_DOWN 
- || mFirstTouchTarget != null) { 
- final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; 
- if (!disallowIntercept) { 
- intercepted = onInterceptTouchEvent(ev); 
- /// M : add log to help debugging 
- if (intercepted == true) { 
- if (DBG_TOUCH) { 
- Xlog.d(TAG, "Touch event was intercepted event = " + ev + ",this = " + this); 
- } 
- } 
- ev.setAction(action); // restore action in case it was changed 
- } else { 
- intercepted = false; 
- } 
- } else { 
- // There are no touch targets and this action is not an initial down 
- // so this view group continues to intercept touches. 
- intercepted = true; 
- } 
- // Check for cancelation. 
- final boolean canceled = resetCancelNextUpFlag(this) 
- || actionMasked == MotionEvent.ACTION_CANCEL; 
- // Update list of touch targets for pointer down, if needed. 
- final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0; 
- if (DBG_MOTION) { 
- Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent 2: actionMasked = " + actionMasked 
- + ",intercepted = " + intercepted + ",canceled = " + canceled + ",split = " 
- + split + ",mChildrenCount = " + mChildrenCount + ",mFirstTouchTarget = " 
- + mFirstTouchTarget + ",this = " + this); 
- } 
- TouchTarget newTouchTarget = null; 
- boolean alreadyDispatchedToNewTouchTarget = false; 
- if (!canceled && !intercepted) { 
- if (actionMasked == MotionEvent.ACTION_DOWN 
- || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) 
- || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { 
- final int actionIndex = ev.getActionIndex(); // always 0 for down 
- final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex) 
- : TouchTarget.ALL_POINTER_IDS; 
- // Clean up earlier touch targets for this pointer id in case they 
- // have become out of sync. 
- removePointersFromTouchTargets(idBitsToAssign); 
- final int childrenCount = mChildrenCount; 
- if (newTouchTarget == null && childrenCount != 0) { 
- final float x = ev.getX(actionIndex); 
- final float y = ev.getY(actionIndex); 
- // Find a child that can receive the event. 
- // Scan children from front to back. 
- final View[] children = mChildren; 
- final boolean customOrder = isChildrenDrawingOrderEnabled(); 
- for (int i = childrenCount - 1; i >= 0; i--) { 
- final int childIndex = customOrder ? 
- getChildDrawingOrder(childrenCount, i) : i; 
- final View child = children[childIndex]; 
- if (!canViewReceivePointerEvents(child) 
- || !isTransformedTouchPointInView(x, y, child, null)) { 
- if (DBG_MOTION) { 
- Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent continue 6: i = " 
- + i + ",count = " + childrenCount + ",child = " + child 
- + ",this = " + this); 
- } 
- continue; 
- } 
- newTouchTarget = getTouchTarget(child); 
- if (DBG_MOTION) { 
- Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent to child 3: child = " 
- + child + ",childrenCount = " + childrenCount + ",i = " + i 
- + ",newTouchTarget = " + newTouchTarget + ",idBitsToAssign = " 
- + idBitsToAssign + ",mFirstTouchTarget = " + mFirstTouchTarget 
- + ",this = " + this); 
- } 
- if (newTouchTarget != null) { 
- // Child is already receiving touch within its bounds. 
- // Give it the new pointer in addition to the ones it is handling. 
- newTouchTarget.pointerIdBits |= idBitsToAssign; 
- break; 
- } 
- resetCancelNextUpFlag(child); 
- if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { 
- // Child wants to receive touch within its bounds. 
- mLastTouchDownTime = ev.getDownTime(); 
- mLastTouchDownIndex = childIndex; 
- mLastTouchDownX = ev.getX(); 
- mLastTouchDownY = ev.getY(); 
- newTouchTarget = addTouchTarget(child, idBitsToAssign); 
- alreadyDispatchedToNewTouchTarget = true; 
- break; 
- } 
- } 
- } 
- if (newTouchTarget == null && mFirstTouchTarget != null) { 
- // Did not find a child to receive the event. 
- // Assign the pointer to the least recently added target. 
- newTouchTarget = mFirstTouchTarget; 
- while (newTouchTarget.next != null) { 
- newTouchTarget = newTouchTarget.next; 
- } 
- newTouchTarget.pointerIdBits |= idBitsToAssign; 
- } 
- } 
- } 
- // Dispatch to touch targets. 
- if (mFirstTouchTarget == null) { 
- // No touch targets so treat this as an ordinary view. 
- handled = dispatchTransformedTouchEvent(ev, canceled, null, 
- TouchTarget.ALL_POINTER_IDS); 
- } else { 
- // Dispatch to touch targets, excluding the new touch target if we already 
- // dispatched to it. Cancel touch targets if necessary. 
- TouchTarget predecessor = null; 
- TouchTarget target = mFirstTouchTarget; 
- while (target != null) { 
- final TouchTarget next = target.next; 
- if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) { 
- handled = true; 
- } else { 
- final boolean cancelChild = resetCancelNextUpFlag(target.child) 
- || intercepted; 
- if (dispatchTransformedTouchEvent(ev, cancelChild, 
- target.child, target.pointerIdBits)) { 
- handled = true; 
- } 
- if (DBG_MOTION) { 
- Xlog.d(TAG, "dispatchTouchEvent middle 5: 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; 
- } 
- } 
- // Update list of touch targets for pointer up or cancel, if needed. 
- if (canceled 
- || actionMasked == MotionEvent.ACTION_UP 
- || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { 
- resetTouchState(); 
- } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) { 
- final int actionIndex = ev.getActionIndex(); 
- final int idBitsToRemove = 1 << ev.getPointerId(actionIndex); 
- removePointersFromTouchTargets(idBitsToRemove); 
- } 
- } 
- if (DBG_MOTION) { 
- Xlog.d(TAG, "(ViewGroup)dispatchTouchEvent end 4: handled = " + handled + ",mFirstTouchTarget = " 
- + mFirstTouchTarget + ",this = " + this); 
- } 
- if (!handled && mInputEventConsistencyVerifier != null) { 
- mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1); 
- } 
- return handled; 
- } 
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。
新闻名称:Android4.4Input模块笔记-创新互联
链接地址:http://www.scyingshan.cn/article/dcgecd.html

 建站
建站
 咨询
咨询 售后
售后
 建站咨询
建站咨询 
 