android View机制深入剖析

以TouchEvent为主,看一下View和ViewGroup内部是如何处理Input Events的;
一、View中TouchEvent的投递过程
    现在版本的Android中、事件处理者已经不由InputEventReceiver来承担,而是通过多种形式的InputStage来进行分别处理。如:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. final class SyntheticInputStage extends InputStage  
  2. final class NativePostImeInputStage extends AsyncInputStage  
  3.       implements InputQueue.FinishedInputEventCallback  
  4. final class ViewPostImeInputStage extends InputStage  
1、InputStage:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\core\java\android\view\ViewRootImpl.java **/  
  2. abstract class InputStage {  
  3.     private final InputStage mNext;  
  4.    
  5.     protected static final int FORWARD = 0;  
  6.     protected static final int FINISH_HANDLED = 1;  
  7.     protected static final int FINISH_NOT_HANDLED = 2;  
  8.    
  9.     /** 
  10.      * Creates an input stage. 
  11.      * @param next The next stage to which events should be forwarded. 
  12.      */  
  13.     public InputStage(InputStage next) {  
  14.         mNext = next;  
  15.     }  
  16.    
  17.     /** 
  18.      * 处理event 
  19.      */  
  20.     public final void deliver(QueuedInputEvent q) {  
  21.     // 有效的event传递给下一stage  
  22.         if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {  
  23.             forward(q);  
  24.         } else if (shouldDropInputEvent(q)) { // 应当被drop的Event  
  25.             finish(q, false);  
  26.         } else {  
  27.             apply(q, onProcess(q));  
  28.         }  
  29.     }  
  30.    
  31.     /** 
  32.      * 标记该event为finished,并传递给下一个stage 
  33.      */  
  34.     protected void finish(QueuedInputEvent q, boolean handled) {  
  35.         q.mFlags |= QueuedInputEvent.FLAG_FINISHED;  
  36.         if (handled) {  
  37.             q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;  
  38.         }  
  39.         forward(q);  
  40.     }  
  41.    
  42.     /** 
  43.      * 将event向前传递给下一个stage 
  44.      */  
  45.     protected void forward(QueuedInputEvent q) {  
  46.         onDeliverToNext(q);  
  47.     }  
  48.    
  49.     /** 
  50.      * 根据result code处理对应的event 
  51.      * Applies a result code from {@link #onProcess} to the specified event. 
  52.      */  
  53.     protected void apply(QueuedInputEvent q, int result) {  
  54.         if (result == FORWARD) {  
  55.             forward(q);  
  56.         } else if (result == FINISH_HANDLED) {  
  57.             finish(q, true);  
  58.         } else if (result == FINISH_NOT_HANDLED) {  
  59.             finish(q, false);  
  60.         } else {  
  61.             throw new IllegalArgumentException("Invalid result: " + result);  
  62.         }  
  63.     }  
  64.    
  65.     /** 
  66.      * 一般继承类会Override该函数 
  67.      * Called when an event is ready to be processed. 
  68.      * @return A result code indicating how the event was handled. 
  69.      */  
  70.     protected int onProcess(QueuedInputEvent q) {  
  71.         return FORWARD;  
  72.     }  
  73.    
  74.     /** 
  75.      * 将event传递给下一stage 
  76.      */  
  77.     protected void onDeliverToNext(QueuedInputEvent q) {  
  78.         if (DEBUG_INPUT_STAGES) {  
  79.             Log.v(TAG, "Done with " + getClass().getSimpleName() + ". " + q);  
  80.         }  
  81.         if (mNext != null) {  
  82.             mNext.deliver(q);  
  83.         } else {  
  84.         // 调用ViewRootImpl的方法  
  85.             finishInputEvent(q);  
  86.         }  
  87.     }  
  88.    
  89.     // 判断是否应该丢弃该Event  
  90.     protected boolean shouldDropInputEvent(QueuedInputEvent q) {  
  91.         if (mView == null || !mAdded) {  
  92.             Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);  
  93.             return true;  
  94.         } else if ((!mAttachInfo.mHasWindowFocus || mStopped)  
  95.                 && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {  
  96.         // 这里是一个focus事件,但当前该window已经不持有input focus,或者已经stopped.  
  97.         // 该情况可能是该event来自于previous stage,但与此同时该window失去了焦点或者已经被停止  
  98.             if (isTerminalInputEvent(q.mEvent)) {  
  99.                 // Don't drop terminal input events, however mark them as canceled.  
  100.                 q.mEvent.cancel();  
  101.                 Slog.w(TAG, "Cancelling event due to no window focus: " + q.mEvent);  
  102.                 return false;  
  103.             }  
  104.    
  105.             // Drop non-terminal input events.  
  106.             Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);  
  107.             return true;  
  108.         }  
  109.         return false;  
  110.     }  
  111.    
  112.     void dump(String prefix, PrintWriter writer) {  
  113.         if (mNext != null) {  
  114.             mNext.dump(prefix, writer);  
  115.         }  
  116.     }  
  117. }  
来重点看一下其继承类ViewPostInmInputStage:

2、ViewPostImeInputStage 

1)ViewPostImeInputStage#onProgress:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\core\java\android\view\ViewRootImpl.java **/  
  2. @Override  
  3. protected int onProcess(QueuedInputEvent q) {  
  4.     if (q.mEvent instanceof KeyEvent) { // 如果是按键事件,processKeyEvent进行处理  
  5.         return processKeyEvent(q);  
  6.     } else {  
  7.         // If delivering a new non-key event, make sure the window is  
  8.         // now allowed to start updating.  
  9.         handleDispatchDoneAnimating();  
  10.         final int source = q.mEvent.getSource();  
  11.         // 通过source即事件源来分类型进行处理  
  12.         if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {  
  13.             return processPointerEvent(q);  
  14.         } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {  
  15.             return processTrackballEvent(q);  
  16.         } else {  
  17.             return processGenericMotionEvent(q);  
  18.         }  
  19.     }  
  20. }  

    当判断是 SOURCE_CLASS_POINTER类型的事件后,会调用processPointerEvent方法进行处理。

2)ViewPostImeInputStage#processPointEvent:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\core\java\android\view\View.java **/  
  2. private int processPointerEvent(QueuedInputEvent q) {  
  3.     final MotionEvent event = (MotionEvent)q.mEvent;  
  4.    
  5.     mAttachInfo.mUnbufferedDispatchRequested = false;  
  6.     // 此时ViewRootImpl会将事件的处理权移交给View树的根节点,调用dispatchPointerEvent函数  
  7.     boolean handled = mView.dispatchPointerEvent(event);  
  8.     if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {  
  9.         mUnbufferedInputDispatch = true;  
  10.         if (mConsumeBatchedInputScheduled) {  
  11.             scheduleConsumeBatchedInputImmediately();  
  12.         }  
  13.     }  
  14.     return handled ? FINISH_HANDLED : FORWARD;  
  15. }  

    ViewRootImpl负责将Event事件传递进来,并根据source的不同进行分类处理;进而将事件的控制权与处理权移交给View树的根View进行dispatchPointerEvent进行处理。


3)View#dispatchPointerEvent:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\core\java\android\view\View.java **/  
  2. public final boolean dispatchPointerEvent(MotionEvent event) {  
  3.     // 按照是否是TouchEvent进行分别处理  
  4.     if (event.isTouchEvent()) {  
  5.         return dispatchTouchEvent(event);  
  6.     } else { // 如果不是调用GenericMotionEvent(Generic——一般的)  
  7.         return dispatchGenericMotionEvent(event);  
  8.     }  
  9. }  
    对于TouchEvent,显然是会调用dispatchTouchEvent进行处理的:

4)View#dispatchTouchEvent
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\core\java\android\view\View.java **/  
  2. public boolean dispatchTouchEvent(MotionEvent event) {  
  3.     ......  
  4.     // 根据安全策略对Touch Event进行过滤  
  5.     if (onFilterTouchEventForSecurity(event)) {  
  6.         //noinspection SimplifiableIfStatement  
  7.     // ListenerInfo中注册了众多的Listener  
  8.         ListenerInfo li = mListenerInfo;  
  9.         if (li != null && li.mOnTouchListener != null  
  10.                 && (mViewFlags & ENABLED_MASK) == ENABLED  
  11.                 && li.mOnTouchListener.onTouch(this, event)) {  
  12.         // 可以看到这里会首先调用TouchListener中的onTouch进行事件处理  
  13.             result = true;  
  14.         }  
  15.    
  16.         // 如果TouchListener中的onTouch返回结果为false的话,View中的onTouchEvent才会继续调用  
  17.         if (!result && onTouchEvent(event)) {  
  18.             result = true;  
  19.         }  
  20.     }  
  21.     ......  
  22.     return result;  
  23. }  
从上面可以看到onTouch与onTouchEvent之间的区别

1>onTouch方法:
onTouch
方法是View OnTouchListener借口中定义的方法。
当一个View绑定了OnTouchLister后,当有touch事件触发时,就会调用onTouch方法。
(当把手放到View上后,onTouch方法被一遍一遍地被调用)

2>onTouchEvent
方法:
onTouchEvent
方法是override Activity的方法。
重新了ActivityonTouchEvent方法后,当屏幕有touch事件时,此方法就会别调用。
(当把手放到Activity上时,onTouchEvent方法就会一遍一遍地被调用)

View 中存在onTouchEvent方法,在定义View的时候重写onTouchEvent可以进行事件处理。


3>touch
事件的传递:
在一个Activity里面放一个TextView的实例tv,并且这个tv的属性设定为 fill_parent
在这种情况下,当手放到屏幕上的时候,首先会是tv响应touch事件,执行onTouch方法。
如果onTouch返回值为true
表示这个touch事件被onTouch方法处理完毕,不会把touch事件再传递给Activity
也就是说onTouchEvent方法不会被调用。
(当把手放到屏幕上后,onTouch方法被一遍一遍地被调用)
如果onTouch的返回值是false
表示这个touch事件没有被tv完全处理,onTouch返回以后,touch事件被传递给Activity
onTouchEvent
方法被调用。


来看一下上面涉及到的几个简单的类:

1>Listener的综合管理类

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\core\java\android\view\View.java **/  
  2. static class ListenerInfo {  
  3.     /** 
  4.      * Listener used to dispatch focus change events. 
  5.      * This field should be made private, so it is hidden from the SDK. 
  6.      * {@hide} 
  7.      */  
  8.     protected OnFocusChangeListener mOnFocusChangeListener;  
  9.    
  10.     /** 
  11.      * Listeners for layout change events. 
  12.      */  
  13.     private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;  
  14.    
  15.     protected OnScrollChangeListener mOnScrollChangeListener;  
  16.    
  17.     /** 
  18.      * Listeners for attach events. 
  19.      */  
  20.     private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;  
  21.    
  22.     /** 
  23.      * Listener used to dispatch click events. 
  24.      * This field should be made private, so it is hidden from the SDK. 
  25.      * {@hide} 
  26.      */  
  27.     public OnClickListener mOnClickListener;  
  28.    
  29.     /** 
  30.      * Listener used to dispatch long click events. 
  31.      * This field should be made private, so it is hidden from the SDK. 
  32.      * {@hide} 
  33.      */  
  34.     protected OnLongClickListener mOnLongClickListener;  
  35.    
  36.     /** 
  37.      * Listener used to build the context menu. 
  38.      * This field should be made private, so it is hidden from the SDK. 
  39.      * {@hide} 
  40.      */  
  41.     protected OnCreateContextMenuListener mOnCreateContextMenuListener;  
  42.    
  43.     private OnKeyListener mOnKeyListener;  
  44.    
  45.     private OnTouchListener mOnTouchListener;  
  46.    
  47.     private OnHoverListener mOnHoverListener;  
  48.    
  49.     private OnGenericMotionListener mOnGenericMotionListener;  
  50.    
  51.     private OnDragListener mOnDragListener;  
  52.    
  53.     private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;  
  54.    
  55.     OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;  
  56. }  
    可以设想到平时所用到的setOnClickListener等设置Listener的方法,就是将ListenerInfo中管理的相关Listener进行初始化。
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\core\java\android\view\View.java **/  
  2. public void setOnClickListener(OnClickListener l) {  
  3.     if (!isClickable()) {  
  4.         setClickable(true);  
  5.     }  
  6.     getListenerInfo().mOnClickListener = l;  
  7. }  
  8.    
  9. ListenerInfo getListenerInfo() {  
  10.     if (mListenerInfo != null) {  
  11.         return mListenerInfo;  
  12.     }  
  13.     mListenerInfo = new ListenerInfo();  
  14.     return mListenerInfo;  
  15. }  
验证了前面的设想。


2>View#onTouchListener:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\core\java\android\view\View.java **/  
  2. /** 
  3.  * Interface definition for a callback to be invoked when a touch event is 
  4.  * dispatched to this view. The callback will be invoked before the touch 
  5.  * event is given to the view. 
  6.  */  
  7. public interface OnTouchListener {  
  8.     /** 
  9.      * Called when a touch event is dispatched to a view. This allows listeners to 
  10.      * get a chance to respond before the target view. 
  11.      * 
  12.      * @param v The view the touch event has been dispatched to. 
  13.      * @param event The MotionEvent object containing full information about 
  14.      *        the event. 
  15.      * @return True if the listener has consumed the event, false otherwise. 
  16.      */  
  17.     boolean onTouch(View v, MotionEvent event);  
  18. }  
    当Acitivity implements OnTouchListner接口时,应当重写该方法;当有Touch Event事件传递进来时,该函数会被首先调用;如果重写的方法返回值为true,onTouchEvent方法将不会被调用;

5)继续来看重要的事件处理方法View#onTouchEvent:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\core\java\android\view\View.java **/  
  2. public boolean onTouchEvent(MotionEvent event) {  
  3.     // 获得触摸点的位置  
  4.     final float x = event.getX();  
  5.     final float y = event.getY();  
  6.     final int viewFlags = mViewFlags;  
  7.    
  8.     if ((viewFlags & ENABLED_MASK) == DISABLED) {  
  9.         if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {  
  10.             setPressed(false);  
  11.         }  
  12.         // 当一个View处于disabled状态时,他仍然会消耗该event事件,但是并不会做出任何响应  
  13.         return (((viewFlags & CLICKABLE) == CLICKABLE ||  
  14.                 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));  
  15.     }  
  16.    
  17.     if (mTouchDelegate != null) {  
  18.         if (mTouchDelegate.onTouchEvent(event)) {  
  19.             return true;  
  20.         }  
  21.     }  
  22.     // 如果View是CLICKABLE或者LONG_CLICKABLE的,继续对event进行处理  
  23.     if (((viewFlags & CLICKABLE) == CLICKABLE ||  
  24.             (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {  
  25.      
  26.     // TouchEvent分为多种类型:ACTION_UP、ACTION_DOWN、ACTION_CANCEL、ACTION_MOVE,对其进行分别响应处理  
  27.         switch (event.getAction()) {  
  28.             case MotionEvent.ACTION_UP:  
  29.                 ......  
  30.                 break;  
  31.    
  32.             case MotionEvent.ACTION_DOWN:  
  33.               ......  
  34.                 break;  
  35.    
  36.             case MotionEvent.ACTION_CANCEL:  
  37.               ......  
  38.                 break;  
  39.    
  40.             case MotionEvent.ACTION_MOVE:  
  41.               ......  
  42.                 break;  
  43.         }  
  44.    
  45.         return true;  
  46.     }  
  47.    
  48.     return false;  
  49. }  
下面分别对其进行分析:
1>ACTION_DOWN:
    一般触摸事件的顺序为ACTION_DOWN->ACTION_UP,或者ACTION_DOWN->ACTION_MOVE->ACTION_UP;可以看到ACTION_DOWN是后续事件的起点。
I、事件具体处理函数
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\core\java\android\view\View.java  
  2.     View#onTouchEvent**/  
  3. case MotionEvent.ACTION_DOWN:  
  4.     // 长按事件标志  
  5.     mHasPerformedLongPress = false;  
  6.    
  7.     if (performButtonActionOnTouchDown(event)) {  
  8.         break;  
  9.     }  
  10.    
  11.     // 判断touch事件是否是在一个scrolling container中.  
  12.     boolean isInScrollingContainer = isInScrollingContainer();  
  13.    
  14.     // For views inside a scrolling container, delay the pressed feedback for  
  15.     // a short period in case this is a scroll.  
  16.     if (isInScrollingContainer) {  
  17.         mPrivateFlags |= PFLAG_PREPRESSED;  
  18.         if (mPendingCheckForTap == null) {  
  19.             mPendingCheckForTap = new CheckForTap();  
  20.         }  
  21.         mPendingCheckForTap.x = event.getX();  
  22.         mPendingCheckForTap.y = event.getY();  
  23.         postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());  
  24.     } else {  
  25.         /** 普通touch事件,进行标志设置 **/  
  26.     // 设置pressed状态  
  27.         setPressed(true, x, y);  
  28.         // 判断是否是LongClick事件  
  29.         checkForLongClick(0);  
  30.     }  
  31.     break;  
    监听到ACTION_DOWN事件,首先后判断是否是在一个Scroller中进行分别处理;如果是普通的Touch事件,会调用serPressed来设置Press状态,同时会根据需要对Touch区域进行重新绘制(比如Button按下的效果);checkForLongClick用来判断是否是长按事件。

II.View#setPressed:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\core\java\android\view\View.java **/  
  2. private void setPressed(boolean pressed, float x, float y) {  
  3.     if (pressed) {  
  4.         drawableHotspotChanged(x, y);  
  5.     }  
  6.    
  7.     setPressed(pressed);  
  8. }  
  9.    
  10. public void setPressed(boolean pressed) {  
  11.     final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED);  
  12.    
  13.     if (pressed) {  
  14.         mPrivateFlags |= PFLAG_PRESSED;  
  15.     } else {  
  16.         mPrivateFlags &= ~PFLAG_PRESSED;  
  17.     }  
  18.    
  19.     // 根据是否需要进行重新UI绘制,绘制函数即为refreshDrawableState  
  20.     if (needsRefresh) {  
  21.         refreshDrawableState();  
  22.     }  
  23.     dispatchSetPressed(pressed);  
  24. }  
setPressed方法主要是设置相关的Pressed标志,并在如果需要重新绘制界面时调用refreshDrawableState进行界面绘制。

III.View#checkForLongClick:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\core\java\android\view\View.java **/  
  2. /** 判断是否是LongClick事件 **/  
  3. private void checkForLongClick(int delayOffset) {  
  4.     if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {  
  5.         mHasPerformedLongPress = false;  
  6.    
  7.         if (mPendingCheckForLongPress == null) {  
  8.             mPendingCheckForLongPress = new CheckForLongPress();  
  9.         }  
  10.         mPendingCheckForLongPress.rememberWindowAttachCount();  
  11.         // 在事件发生规定时间(即定义为Long Click的最短长按时间)后,Post一个判断是否是Long Click的Runnable  
  12.         // 如果是Long Click事件,该Runnable会进行相应的处理;  
  13.         // 在后面将会看到,如果TIME_OUT之前有ACTION_UP或者ACTION_MOVE事件发生,则会调用removeLongPressCallback();移除这个Runnable  
  14.         postDelayed(mPendingCheckForLongPress,  
  15.                 ViewConfiguration.getLongPressTimeout() - delayOffset);  
  16.     }  
  17. }  
  18.    
  19. private CheckForLongPress mPendingCheckForLongPress;  
  20.    
  21. /** 判断是否是Long Click事件的线程  **/  
  22. private final class CheckForLongPress implements Runnable {  
  23.     private intmOriginalWindowAttachCount;  
  24.    
  25.     @Override  
  26.     public void run() {  
  27.     // 判断是否仍处于Pressed状态  
  28.         if (isPressed() && (mParent != null)  
  29.                 && mOriginalWindowAttachCount == mWindowAttachCount) {  
  30.         // 表明当前是Long Click事件,对其进行Long Click响应  
  31.             if (performLongClick()) {  
  32.                 mHasPerformedLongPress = true;  
  33.             }  
  34.         }  
  35.     }  
  36.    
  37.     public void rememberWindowAttachCount() {  
  38.         mOriginalWindowAttachCount = mWindowAttachCount;  
  39.     }  
  40. }  
  41.    
  42. /** Long Click事件响应函数 **/  
  43. public boolean performLongClick() {  
  44.     sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);  
  45.    
  46.     // 通过调用OnLongClickListener进行响应  
  47.     boolean handled = false;  
  48.     ListenerInfo li = mListenerInfo;  
  49.     if (li != null && li.mOnLongClickListener != null) {  
  50.         handled = li.mOnLongClickListener.onLongClick(View.this);  
  51.     }  
  52.     if (!handled) {  
  53.         handled = showContextMenu();  
  54.     }  
  55.     if (handled) {  
  56.         performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);  
  57.     }  
  58.     return handled;  
  59. }  

2>ACTION_MOVE:
ACTION_MOVE事件是由于用户按下并拖动的结果,知道产生ACTION_UP或者ACTION_CANCEL事件结束;
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. case MotionEvent.ACTION_MOVE:  
  2.     /** @Value获得触摸点的位置,注:每个移动都会源源不断地产生很多ACTION_MOVE事件 
  3.      *  final float x = event.getX(); 
  4.         final float y = event.getY();*/  
  5.     drawableHotspotChanged(x, y);  
  6.    
  7.     // 用以判断当前收拾是否已经超出了该View的范围  
  8.     if (!pointInView(x, y, mTouchSlop)) {  
  9.         // 如果超出了View的范围,则撤销ACTION_DOWN中的所有设置  
  10.         removeTapCallback();  
  11.         if ((mPrivateFlags & PFLAG_PRESSED) != 0) {  
  12.             // 撤销Long Click状态  
  13.             removeLongPressCallback();  
  14.             // 撤销Click状态  
  15.             setPressed(false);  
  16.         }  
  17.     }  
  18.     break;  


3>ACTION_UP:
ACTION_UP是手势的结束点。其处理函数最重要的就是判断是否会产生Click;
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. case MotionEvent.ACTION_UP:  
  2.     // 判断是否是pressed状态  
  3.     boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;  
  4.     if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {  
  5.         // take focus if we don't have it already and we should in  
  6.         // touch mode.  
  7.         boolean focusTaken = false;  
  8.         if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {  
  9.             focusTaken = requestFocus();  
  10.         }  
  11.    
  12.         if (prepressed) {  
  13.             setPressed(true, x, y);  
  14.        }  
  15.    
  16.         /** 如果是Long Click,这里就不会产生Click **/  
  17.         if (!mHasPerformedLongPress) { // 非Long Click状态  
  18.             // 撤销Long Click的Runnable线程  
  19.             removeLongPressCallback();  
  20.    
  21.             /** 只有处于pressed状态,才会进行click操作 **/  
  22.             if (!focusTaken) {  
  23.                 // Use a Runnable and post this rather than calling  
  24.                 // performClick directly. This lets other visual state  
  25.                 // of the view update before click actions start.  
  26.               // 创建一个PerformClick(Runnable),该Runnable的run函数主体就是performClick  
  27.                 if (mPerformClick == null) {  
  28.                     mPerformClick = new PerformClick();  
  29.                 }  
  30.                 // 将该线程post,如果post不成功,直接执行官performClick  
  31.                 // 可以看到performClick并不会立即执行,而是添加到队列中,等待前面执行完毕,才会执行  
  32.                 if (!post(mPerformClick)) {  
  33.                     performClick();  
  34.                 }  
  35.             }  
  36.         }  
  37.    
  38.         /** PressedStateDuration时间之后撤销PressedState状态 **/  
  39.         if (mUnsetPressedState == null) {  
  40.             mUnsetPressedState = new UnsetPressedState();  
  41.         }  
  42.    
  43.         if (prepressed) {  
  44.             postDelayed(mUnsetPressedState,  
  45.                     ViewConfiguration.getPressedStateDuration());  
  46.         } elseif (!post(mUnsetPressedState)) {  
  47.             // If the post failed, unpress right now  
  48.             mUnsetPressedState.run();  
  49.         }  
  50.    
  51.         removeTapCallback();  
  52.     }  
  53.     break;  


4>ACTION_CANCEL:
    ACTION_CANCEL事件并不是由用户主动产生的,而是系统谨慎判断之后的结果,说明当前手势已经被废弃,则接下来执行清理操作。
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. case MotionEvent.ACTION_CANCEL:  
  2.     setPressed(false);  
  3.     removeTapCallback();  
  4.     removeLongPressCallback();  
  5.     break;  

二、InputManagerService:
    前面提到了ViewRootImpl对TouchEvent事件的处理流程,那这些事件又是怎么来的。事件的来源可以分为“软件”,“硬件”两种;
主要的事件包含有:
案件事件(KeyEvent)    :即物理按键按下产生的事件,相关的常用物理按键一般有HOME,BACK等
触摸事件(TouchEvent): 
鼠标事件(MouseEvent)、轨迹球事件(TrackBallEvent)(这两个已经不常见);

针对所有事件的共性抽象出了InputEvent接口;其有两个子类:KeyEvent,MotionEvent;

1、事件的投递流程

1>源信息采集
    对“硬件源”产生的原始信息进行收集;它需要Linux内核驱动的支持,Android系统通过/dev/input下的节点来访问当前发生的事件。
2>前期处理
    对收集到信息进行筛选以及格式转化
3>WMS分配
    WMS是窗口的Manager,同时也是InputEvent的派发者。
4>应用程序处理

2、InputManagerService启动:
    InputManagerService同样也是有SystemServer进程启动,这个在Android启动过程——init.rc,Zygote,SystemServer中已经提到过:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** @path: \frameworks\base\services\java\com\android\server\SystemServer.java */    
  2. class ServerThread extends Thread {   
  3.     @Override   
  4.     public void run() {   
  5.     // 可以看到IMS和WMS是紧密相关的  
  6.     ......  
  7.     // @value InputManagerService inputManager  
  8.         inputManager = new InputManagerService(context, wmHandler);  
  9.    
  10.         Slog.i(TAG, "Window Manager");  
  11.         // @value WindowManagerService wm  
  12.         wm = WindowManagerService.main(context, power, display, inputManager,  
  13.                 uiHandler, wmHandler,  
  14.                 factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,  
  15.                 !firstBoot, onlyCore);  
  16.         ServiceManager.addService(Context.WINDOW_SERVICE, wm);  
  17.         ServiceManager.addService(Context.INPUT_SERVICE, inputManager);  
  18.    
  19.         ActivityManagerService.self().setWindowManager(wm);  
  20.    
  21.         inputManager.setWindowManagerCallbacks(wm.getInputMonitor());  
  22.         inputManager.start();  
  23.         .....  
  24.     }  
  25. }  

4、InputMangerService:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\services\core\java\com\android\server\input\InputManagerService.java **/  
  2. public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {  
  3.     // 指向native端IMS类对象的地址  
  4.     private final long mPtr;  
  5.      
  6.     public InputManagerService(Context context) {  
  7.         this.mContext = context;  
  8.         this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());  
  9.          
  10.         mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);  
  11.          
  12.         // 创建native IMS对象  
  13.         mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());  
  14.          
  15.         LocalServices.addService(InputManagerInternal.classnew LocalService());  
  16.     }  
  17. }  

可以看到Java层的IMS实际上只是对Native层的InputManager的一层包装;其创建主要是native层进行创建。


5、native层的InputManagerService——NativeInputManager类
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp **/  
  2. class NativeInputManager : public virtual RefBase,  
  3.     public virtual InputReaderPolicyInterface,  
  4.     public virtual InputDispatcherPolicyInterface,  
  5.     public virtual PointerControllerPolicyInterface  
  6.   
  7. static jlong nativeInit(JNIEnv* env, jclass clazz,  
  8.         jobject serviceObj, jobject contextObj, jobject messageQueueObj) {  
  9.     // 创建一个Message Queue  
  10.     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);  
  11.     if (messageQueue == NULL) {  
  12.         jniThrowRuntimeException(env, "MessageQueue is not initialized.");  
  13.         return 0;  
  14.     }  
  15.    
  16.     // 可以看到NativeInputManager中包含有一个Looper,用以进行事件分派  
  17.     NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,  
  18.             messageQueue->getLooper());  
  19.     im->incStrong(0);  
  20.     // 返回创建的IMS实例对象的地址(强制转化为long类型)  
  21.     return reinterpret_cast<jlong>(im);  
  22. }  
创建完实例后,进一步调用start函数,来看一下start函数所完成的功用。

3、InputManagerService#start:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\services\core\java\com\android\server\input\InputManagerService.java **/  
  2. public void start() {  
  3.     ......  
  4.     nativeStart(mPtr);  
  5.     ......  
  6. }  
  7. private static native void nativeStart(long ptr);  
     可以看到start仅是对nativeStart本地方法进行封装。

4、NativeInputManager#nativeStart:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp **/  
  2. static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {  
  3.     // ptr为创建的IMS实例的地址,这里将其强制转化成为NativeInputManager类  
  4.     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);  
  5.    
  6.     // 这里进一步调用InputManager的star方法  
  7.     status_t result = im->getInputManager()->start();  
  8.     if (result) {  
  9.         jniThrowRuntimeException(env, "Input manager could not be started.");  
  10.     }  
  11. }  
  12. // @value sp<InputManager> mInputManager;  
  13. inline sp<InputManager> getInputManager() const { return mInputManager; }  
可以看到这里进一步调用了InputManager的start方法;IMS在Native层的主要实现实体其实是InputManager。

5、InputManager#start
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputManager.cpp **/  
  2. class InputManagerInterface : public virtual RefBase {  
  3.     private:  
  4.         sp<InputReaderInterface> mReader;  
  5.         sp<InputReaderThread> mReaderThread;  
  6.      
  7.         sp<InputDispatcherInterface> mDispatcher;  
  8.         sp<InputDispatcherThread> mDispatcherThread;  
  9.      
  10.     // 构造函数  
  11.     InputManager::InputManager(  
  12.             const sp<EventHubInterface>& eventHub,  
  13.             const sp<InputReaderPolicyInterface>& readerPolicy,  
  14.             const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {  
  15.         mDispatcher = new InputDispatcher(dispatcherPolicy);  
  16.         mReader = new InputReader(eventHub, readerPolicy, mDispatcher);  
  17.         initialize();  
  18.     }  
  19.      
  20.     /*** 进行初始化 **/  
  21.     void InputManager::initialize() {  
  22.         // 创建两个Thread的实例  
  23.         mReaderThread = new InputReaderThread(mReader);  
  24.         mDispatcherThread = new InputDispatcherThread(mDispatcher);  
  25.     }  
  26.      
  27.     // start函数  
  28.     status_t InputManager::start() {  
  29.         // 可以看到这里会开启两个线程mDispatcherThread,与mReaderThread  
  30.         // 分别对应InputReaderThread,InputDispatcherThread  
  31.         status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);  
  32.         ......  
  33.         result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);  
  34.         if (result) {  
  35.             mDispatcherThread->requestExit();  
  36.             return result;  
  37.         }     
  38.         return OK;  
  39.     }  
  40. };  
    可以看到 start函数中开启了两个native端的线程:InputReaderThread和InputDispatcherThread;从名称可以简单推断出前者用以读取Input事件,后者用以对事件进行处理分发。

<一> InputReaderThread

1、InputReaderThread类

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputReader.h **/  
  2. /** 无限循环从event hub中读取event,然后读取processes他们  */  
  3. class InputReaderThread : public Thread {  
  4. public:  
  5.     InputReaderThread(const sp<InputReaderInterface>& reader);  
  6.     virtual ~InputReaderThread();  
  7.    
  8. private:  
  9.     sp<InputReaderInterface> mReader;  
  10.     /** 继承Thread的子类必须实现该函数,因为这个其实是Thread的真正执行函数 **/  
  11.     // Derived class must implement threadLoop(). The thread starts its life  
  12.     // here. There are two ways of using the Thread object:  
  13.     // 1) loop: if threadLoop() returns true, it will be called again if  
  14.     //          requestExit() wasn't called.  
  15.     // 2) once: if threadLoop() returns false, the thread will exit upon return.  
  16.     virtual bool threadLoop();  
  17. };  


2、InputReaderThread类的具体实现
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputReader.cpp **/  
  2. InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :  
  3.         Thread(/*canCallJava*/true), mReader(reader) {  
  4.     // 这里初始化重要变量sp<InputReaderInterface> mReader  
  5. }  
  6.    
  7. bool InputReaderThread::threadLoop() {  
  8.     // 调用mReader中的loopOnce函数,可以看出InputReaderInterface是该类的核心  
  9.     mReader->loopOnce();  
  10.     return true;  
  11. }  
可以看到InputReaderThread类的最重要实现在于InputReaderInterface,该类为核心(其运行时类型为InputReader);

3、InputReaderInterface:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputReader.h **/  
  2. class InputReaderInterface : public virtual RefBase  
  3. class InputReader : public InputReaderInterface  
  4.    
  5. /** \frameworks\native\services\inputflinger\InputReader.cpp **/  
  6. // loopOnce即事件处理函数  
  7. void InputReader::loopOnce() {  
  8.     ......  
  9.     // 其实是通过mEventHub来获取Events的  
  10.     // @value sp<EventHubInterface> mEventHub;  
  11.     size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);  
  12.     ......      
  13.     // @value sp<QueuedInputListener> mQueuedListener;  
  14.     mQueuedListener->flush();  
  15. }  
EventHubInterface定义在EventHub.h中,其getEvents是通过读取/dev/input/下的相关文件来判断是否有新事件,进而通给值InputReader

<二>InputDispatcherThread:
    同理该线程的实现核心为InputDispatcher类,进行事件的派发和处理。
1、InputDispatcherThread定义
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputDispatcher.h **/  
  2. class InputDispatcherThread : public Thread {  
  3. public:  
  4.     explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher);  
  5.     ~InputDispatcherThread();  
  6.    
  7. private:  
  8.     virtual boolthreadLoop();  
  9.    
  10.     sp<InputDispatcherInterface> mDispatcher;  
  11. };  
  12.    
  13. bool InputDispatcherThread::threadLoop() {  
  14.     mDispatcher->dispatchOnce();  
  15.     return true;  
  16. }  

2、InputDispatcher定义:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputDispatcher.h **/  
  2. class InputDispatcher : public InputDispatcherInterface  
  3.    
  4. class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface  
可以看到 InputDispatcherInterface 最终继承一个 InputListenerInterface 类;该类明显是一个Listener

3、InputManager构造函数
    回到前面Native层的IMS(InputManager)构造函数:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputManager.cpp **/  
  2. InputManager::InputManager(  
  3.         const sp<EventHubInterface>& eventHub,  
  4.         const sp<InputReaderPolicyInterface>& readerPolicy,  
  5.         const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {  
  6.     mDispatcher = new InputDispatcher(dispatcherPolicy);  
  7.     // 这里初始化InputReader时就将InputReader与InputDispatcher建立起了关联  
  8.     mReader = new InputReader(eventHub, readerPolicy, mDispatcher);  
  9.     initialize();  
  10. }  
    可以看到这里最开始就将InputDispatcher与InputReader建立起关联;接下来看InputReader的构造函数,看两者是怎样建立起关联的:

4、InputReader构造函数
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputReader.cpp **/  
  2. InputReader::InputReader(const sp<EventHubInterface>& eventHub,  
  3.         const sp<InputReaderPolicyInterface>& policy,  
  4.         const sp<InputListenerInterface>& listener) :  
  5.         mContext(this), mEventHub(eventHub), mPolicy(policy),  
  6.         mGlobalMetaState(0), mGeneration(1),  
  7.         mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),  
  8.         mConfigurationChangesToRefresh(0) {  
  9.     // 这里将mDispatcher当做InputListenerInterface类型,初始化QueueInputListener  
  10.     mQueuedListener = new QueuedInputListener(listener);  
  11.    
  12.     { // acquire lock  
  13.         AutoMutex _l(mLock);  
  14.    
  15.         refreshConfigurationLocked(0);  
  16.         updateGlobalMetaStateLocked();  
  17.     } // release lock  
  18. }  
而上面2中提到InputDispatcher继承了InputListenerInterface,这里可以看到InputReader使用mDispatcher来初始化mQueueListener(QueueInputListener类);
这个mQueueListener前面就见到过,在InputReader::loopOnce()事件获取函数中,通过Event Hub获取到event事件,然后调用mQueuedListener->flush();

5、QueueInputListener#flush:
1)先看QueueInputListener的定义
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputListener.h **/  
  2. class QueuedInputListener : public InputListenerInterface {  
  3. protected:  
  4.     virtual ~QueuedInputListener();  
  5.    
  6. public:  
  7.     QueuedInputListener(const sp<InputListenerInterface>& innerListener);  
  8.    
  9.     virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);  
  10.     virtual void notifyKey(const NotifyKeyArgs* args);  
  11.     virtual void notifyMotion(const NotifyMotionArgs* args);  
  12.     virtual void notifySwitch(const NotifySwitchArgs* args);  
  13.     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);  
  14.    
  15.     void flush();  
  16.    
  17. private:  
  18.     sp<InputListenerInterface> mInnerListener;// mInnerListner即是InputDispatcher  
  19.     Vector<NotifyArgs*> mArgsQueue; // 后面flush函数中将会用到  
  20. };  
可以看到这里可以向InputReader注册监听很多事件。

2)flush函数
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputListener.cpp **/  
  2. void QueuedInputListener::flush() {  
  3.     size_t count = mArgsQueue.size();  
  4.     for (size_t i = 0; i < count; i++) {  
  5.         NotifyArgs* args = mArgsQueue[i];  
  6.         // 调用NotifyArgs。notify函数  
  7.         args->notify(mInnerListener);  
  8.         delete args;  
  9.     }  
  10.     mArgsQueue.clear();  
  11. }  
  12. // 这里仅是一个封装函数,最终调用InputListenerInterface的notifyKey函数  
  13. void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {  
  14.     listener->notifyKey(this);  
  15. }  

    最终调用InputListenerInterface(即InputDispatcher)的notifyKey回调函数;

    总结前面的流程即InputReaderThread通过EventHub不断读取获取event信息,获得事件后,调用InputDispather的notifyKey函数来通知InputDispathcer进行处理。
其具体的流程:


<三>事件处理流程
1、InputDispatcher::notifyKey:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/  
  2. void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {  
  3.     if (!validateKeyEvent(args->action)) { // 判断event是否合法  
  4.         return;  
  5.     }  
  6.     ......  
  7.     // 初始化KeyEvent  
  8.     KeyEvent event;  
  9.     event.initialize(args->deviceId, args->source, args->action,  
  10.             flags, keyCode, args->scanCode, metaState, 0,  
  11.             args->downTime, args->eventTime);  
  12.    
  13.     { // acquire lock  
  14.         mLock.lock();  
  15.         ......  
  16.         KeyEntry* newEntry = new KeyEntry(args->eventTime,  
  17.                 args->deviceId, args->source, policyFlags,  
  18.                 args->action, flags, keyCode, args->scanCode,  
  19.                 metaState, repeatCount, args->downTime);  
  20.         // 继续调用enqueueInboundEventLocked函数  
  21.         needWake = enqueueInboundEventLocked(newEntry);  
  22.         mLock.unlock();  
  23.     } // release lock  
  24. }  

2、InputDispatcher::enqueueInboundEventLocked:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/  
  2. bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {  
  3.     // @value Queue<EventEntry> mInboundQueue;  
  4.     bool needWake = mInboundQueue.isEmpty();  
  5.     // 将entry入队列  
  6.     mInboundQueue.enqueueAtTail(entry);  
  7.    
  8.     switch (entry->type) { // 如前面所述,InputEvent分为KeyEvent和MotionEvent进行分别处理  
  9.     case EventEntry::TYPE_KEY: ......  
  10.    
  11.     case EventEntry::TYPE_MOTION: .....  
  12.     }  
  13.    
  14.     return needWake;  
  15. }  
当InputReader读取到一个event之后,最终enqueue进mInboundQueue消息队列中;接下来看怎么处理;

前面InputDispatcherThread的运行函数threadLoop,其主体是调用InputDispatcher中的dispatchOnce进行处理,可想而知,消息处理函数自然在dispatchOnce中;

3、InputDispatcher::dispatchOnce:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/  
  2. void InputDispatcher::dispatchOnce() {  
  3.     nsecs_t nextWakeupTime = LONG_LONG_MAX;  
  4.     { // acquire lock  
  5.         AutoMutex _l(mLock);  
  6.         mDispatcherIsAliveCondition.broadcast();  
  7.    
  8.         // 在没有等待的commands事运行一个dispatch loop,这个loop之后可能enqueue commands  
  9.         if (!haveCommandsLocked()) {  
  10.             dispatchOnceInnerLocked(&nextWakeupTime);  
  11.         }  
  12.    
  13.         // 如果有等待的commands的话,就运行所有的commands  
  14.         // If any commands were run then force the next poll to wake up immediately.  
  15.         if (runCommandsLockedInterruptible()) {  
  16.             nextWakeupTime = LONG_LONG_MIN;  
  17.         }  
  18.     } // release lock  
  19.    
  20.     // Wait for callback or timeout or wake.  (make sure we round up, not down)  
  21.     nsecs_t currentTime = now();  
  22.     int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);  
  23.     mLooper->pollOnce(timeoutMillis);  
  24. }  
继续来看dispatchOnceInnerLocked函数;

4、InputDispathcer#dispatchOnceInnerLocked:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/  
  2. void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {  
  3.     .......  
  4.     // 根据mPendingEvent的Type的不同分别进行处理  
  5.     switch (mPendingEvent->type) {  
  6.     case EventEntry::TYPE_CONFIGURATION_CHANGED: {  
  7.     ......  
  8.         done = dispatchConfigurationChangedLocked(currentTime, typedEntry);  
  9.         dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped  
  10.         break;  
  11.     }  
  12.    
  13.     case EventEntry::TYPE_DEVICE_RESET: {  
  14.     ......  
  15.         done = dispatchDeviceResetLocked(currentTime, typedEntry);  
  16.         dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped  
  17.         break;  
  18.     }  
  19.    
  20.     // KeyEvent采用dispatchKeyLocked进行处理  
  21.     case EventEntry::TYPE_KEY: {  
  22.         KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);  
  23.         ......  
  24.         done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);  
  25.         break;  
  26.     }  
  27.    
  28.     // MotionEvent采用dispatchMotionLocked进行处理  
  29.     case EventEntry::TYPE_MOTION: {  
  30.         ......  
  31.         done = dispatchMotionLocked(currentTime, typedEntry,  
  32.                 &dropReason, nextWakeupTime);  
  33.         break;  
  34.     }  
  35.    
  36.     default:  
  37.         ALOG_ASSERT(false);  
  38.         break;  
  39.     }  
  40. }  
    针对Event的type的不同进行不同的处理,KeyEvent采用dispatchKeyLocked进行处理,MotionEvent采用dispatchMotionLocked进行处理;下面以KeyEvent为例进行分析,下面忽略对event的具体处理细节,具体来看事件是如何传递的;

5、InputDispatcher::dispatchKeyLocked:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/  
  2. bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,  
  3.         DropReason* dropReason, nsecs_t* nextWakeupTime) {  
  4.     ......  
  5.     /** 确定事件的接收方(Target) **/  
  6.     Vector<InputTarget> inputTargets;  
  7.     int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,  
  8.             entry, inputTargets, nextWakeupTime);  
  9.    
  10.     setInjectionResultLocked(entry, injectionResult);  
  11.     addMonitoringTargetsLocked(inputTargets);  
  12.    
  13.     /** 将消息dispatch给Target **/  
  14.     dispatchEventLocked(currentTime, entry, inputTargets);  
  15.     return true;  
  16. }  
前面对event的处理忽略掉,重点来看系统是如何查找event对应的接收方(Target)的,接下来分析函数findFocusedWindowTargetsLocked

6、InputDispatcher::findFocusedWindowTargetsLocked:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/  
  2. int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,  
  3.         const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {  
  4.     int32_t injectionResult;  
  5.     String8 reason;  
  6.     // mFocusedWindowHandle表示当前焦点窗口的句柄  
  7.     // @value sp<InputWindowHandle> mFocusedWindowHandle;  
  8.     /** 当获得焦点的窗口为null时,会丢弃这一事件 **/  
  9.     if (mFocusedWindowHandle == NULL) {  
  10.         if (mFocusedApplicationHandle != NULL) {  
  11.         // 如果没有焦点窗口,但焦点窗口所在的应用程序进程存在,说明该应程序还在启动过程中,故等待nextWakeupTime后再重试  
  12.             injectionResult = handleTargetsNotReadyLocked(currentTime, entry,  
  13.                     mFocusedApplicationHandle, NULL, nextWakeupTime,  
  14.                     "Waiting because no window has focus but there is a "  
  15.                     "focused application that may eventually add a window "  
  16.                     "when it finishes starting up.");  
  17.             goto Unresponsive;  
  18.         }  
  19.    
  20.         injectionResult = INPUT_EVENT_INJECTION_FAILED;  
  21.         goto Failed;  
  22.     }  
  23.    
  24.     /** 如果执行到这里说明当前有焦点窗口 **/  
  25.     // 先判断权限  
  26.     if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {  
  27.         injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;  
  28.         goto Failed;  
  29.     }  
  30.    
  31.     // 如果当前焦点窗口正在处理上一个事件,采取和最上面一样的作法,等待一段时间后重试  
  32.     reason = checkWindowReadyForMoreInputLocked(currentTime,  
  33.             mFocusedWindowHandle, entry, "focused");  
  34.     if (!reason.isEmpty()) {  
  35.         injectionResult = handleTargetsNotReadyLocked(currentTime, entry,  
  36.                 mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());  
  37.         goto Unresponsive;  
  38.     }  
  39.    
  40.     // 成功找到匹配的窗口,通过addWindowTargetLocked添加到inputTargets变量中  
  41.     injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;  
  42.     addWindowTargetLocked(mFocusedWindowHandle,  
  43.             InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),  
  44.             inputTargets);  
  45.    
  46. Failed:  
  47. Unresponsive:  
  48.     nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);  
  49.     updateDispatchStatisticsLocked(currentTime, entry,  
  50.             injectionResult, timeSpentWaitingForApplication);  
  51.     return injectionResult;  
  52. }  
     上面获取到目标窗口的流程较为清晰简单,其主要的变量是mFocusedWindowHandle,它表示焦点窗口的句柄,而InputDispatcher又是如何获取到它的。

这里先引出InputMonitor的概念,它是WMS与InputDispatcher的中介;WMS通过InputMonitor的updateInputWindowsLw来告知InputDispatcher中的当前焦点窗口了;其具体的代码调动流程如下: 
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\services\core\java\com\android\server\wm\InputMonitor.java **/  
  2. /* Updates the cached window information provided to the input dispatcher. */  
  3. public void updateInputWindowsLw(boolean force) {  
  4.     ......  
  5.     // Send windows to native code.  
  6.     // @value private final WindowManagerService mService;  
  7.     // @value final InputManagerService mInputManager;  
  8.     mService.mInputManager.setInputWindows(mInputWindowHandles);  
  9.     ......  
  10. }  
  11.    
  12. /** \frameworks\base\services\core\java\com\android\server\input\InputManagerService.java **/  
  13. public void setInputWindows(InputWindowHandle[] windowHandles) {  
  14.     nativeSetInputWindows(mPtr, windowHandles);  
  15. }  
  16. private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles);  
  17.    
  18.    
  19. /** \frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp **/  
  20. static void nativeSetInputWindows(JNIEnv* env, jclass clazz,  
  21.         jlong ptr, jobjectArray windowHandleObjArray) {  
  22.     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);  
  23.    
  24.     im->setInputWindows(env, windowHandleObjArray);  
  25. }  
  26.    
  27. /*-----NativeInputManager-----*/  
  28. void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {  
  29.     Vector<sp<InputWindowHandle> > windowHandles;  
  30.     ......  
  31.     // @value sp<InputManager> mInputManager;  
  32.     mInputManager->getDispatcher()->setInputWindows(windowHandles);  
  33.     ......  
  34. }  
  35.    
  36.    
  37. /** \frameworks\native\services\inputflinger\InputManager.cpp **/  
  38. sp<InputDispatcherInterface> InputManager::getDispatcher() {  
  39.     return mDispatcher;  
  40. }  
  41.    
  42. /** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/  
  43. void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {  
  44.     { // acquire lock  
  45.         AutoMutex _l(mLock);  
  46.    
  47.         Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;  
  48.         mWindowHandles = inputWindowHandles;  
  49.    
  50.         sp<InputWindowHandle> newFocusedWindowHandle;  
  51.         ......  
  52.         // 一系列处理  
  53.         mFocusedWindowHandle = newFocusedWindowHandle;  
  54.         .....  
  55.     } // release lock  
  56.    
  57.     // Wake up poll loop since it may need to make new input dispatching choices.  
  58.     mLooper->wake();  
  59. }  

可以看到这里涉及到了InputMonitor、WMS与IMS之间的交互;

找到了InputTarget,InputDispatcher又是如何与之通信的?

7、InputTarget:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\services\inputflinger\InputDispatcher.h **/  
  2. /* 
  3.  * An input target specifies how an input event is to be dispatched to a particular window 
  4.  * including the window's input channel, control flags, a timeout, and an X / Y offset to 
  5.  * be added to input event coordinates to compensate for the absolute position of the 
  6.  * window area. 
  7.  */  
  8. structInputTarget {  
  9.     enum { // 该枚举类列举个关于目标窗口的各种属性值描述  
  10.         /* This flag indicates that the event is being delivered to a foreground application. */  
  11.         FLAG_FOREGROUND = 1 << 0, // 说明目标窗口是前台应用  
  12.         ......  
  13.     }  
  14.     /** InputDispatcher与WMS建立关联通信的地方 */  
  15.     sp<InputChannel> inputChannel;  
  16. };  
这里引出了重要的类InputChannel,InputDispatcher与WMS也是跨进程通信的,其通过InputChannel进行通信。

<四>InputChannel:

 1、InputChannel:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\include\input\InputTransport.h **/  
  2. /* 
  3.  * An input channel consists of a local unix domain socket used to send and receive 
  4.  * input messages across processes.  Each channel has a descriptive name for debugging purposes. 
  5.  * 
  6.  * Each endpoint has its own InputChannel object that specifies its file descriptor. 
  7.  * 
  8.  * The input channel is closed when all references to it are released. 
  9.  */  
  10. // 上面提到InputChannel是使用unix domain socket(UDS)进行通信的,而非Binder  
  11. class InputChannel : public RefBase {  
  12. protected:  
  13.     virtual~InputChannel();  
  14.    
  15.    
  16. public:  
  17.     InputChannel(const String8& name, int fd); // fd类似设备描述符  
  18.     // 用于打开一个InputChannel对(Pair),用以实现双向通信  
  19.     static status_t openInputChannelPair(const String8& name,  
  20.             sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);  
  21.    
  22.     inline String8 getName() const { returnmName; }  
  23.     inlineint getFd() const { returnmFd; }  
  24.    
  25.     // 发送接收信息  
  26.     status_t sendMessage(const InputMessage* msg);  
  27.     status_t receiveMessage(InputMessage* msg);  
  28.    
  29.     /* Returns a new object that has a duplicate of this channel's fd. */  
  30.     sp<InputChannel> dup() const;  
  31.    
  32. private:  
  33.     String8 mName;  
  34.     int mFd;  // 重点要弄清该变量代表的含义  
  35. };  
上面提到InputChannel是使用UDS进行通信的,Android系统中最为常用的进程间通信时Binder通信,其次便是UDS进行单机内的进程间通信,也称IPC Socket。下面进行验证。

2、从源头开看InputChannel的创建初始化
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java **/  
  2. public int addWindow(Session session, IWindow client, int seq,  
  3.         WindowManager.LayoutParams attrs, int viewVisibility, int displayId,  
  4.         Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel) {  
  5.     ......  
  6.     if (outInputChannel != null && (attrs.inputFeatures  
  7.             & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
  8.     // 设置当前的通道名  
  9.         String name = win.makeInputChannelName();  
  10.         // 打开一对InputChannel通道  
  11.         InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);  
  12.         win.setInputChannel(inputChannels[0]);  
  13.         inputChannels[1].transferTo(outInputChannel);  
  14.    
  15.         mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);  
  16.     }  
  17.     ......  
  18. }  

3、InputChannel#openInputChannelPair
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\base\core\java\android\view\InputChannel.java **/  
  2. public static InputChannel[] openInputChannelPair(String name) {  
  3.     if (name == null) {  
  4.         throw new IllegalArgumentException("name must not be null");  
  5.     }  
  6.     return nativeOpenInputChannelPair(name);  
  7. }  
  8.    
  9. private static native InputChannel[] nativeOpenInputChannelPair(String name);  

4、InputChannel::openInputChannelPair:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** \frameworks\native\libs\input\InputTransport.cpp **/  
  2. status_t InputChannel::openInputChannelPair(const String8& name,  
  3.         sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {  
  4.     // 建立UDS  
  5.     int sockets[2];  
  6.     if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {  
  7.         status_t result = -errno;  
  8.         outServerChannel.clear();  
  9.         outClientChannel.clear();  
  10.         return result;  
  11.     }  
  12.    
  13.     // 设置缓冲区大小  
  14.     int bufferSize = SOCKET_BUFFER_SIZE;  
  15.     setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));  
  16.     setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));  
  17.     setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));  
  18.     setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));  
  19.    
  20.     // 创建Server与Client端实例  
  21.     String8 serverChannelName = name;  
  22.     serverChannelName.append(" (server)");  
  23.     outServerChannel = new InputChannel(serverChannelName, sockets[0]);  
  24.    
  25.     String8 clientChannelName = name;  
  26.     clientChannelName.append(" (client)");  
  27.     outClientChannel = new InputChannel(clientChannelName, sockets[1]);  
  28.     return OK;  
  29. }  
这里可以看到IMS与WMS之间是通过InputChannel,使用UDS进行进程间通信的;

    上面整理的流程可以简单概括为IMS中有两个event时间相关的线程InputReaderThread和InputDispatcherThread;
InputReaderThread通过EventHub读取/dev/input/下是否有新事件产生,然后传递给InputDispatcherThread,该Thread通过InputMonitor与WMS建立关联,确定当前焦点窗口,来选择匹配的InputTarget,进而将该event通过InputChannel传递给对应Target进行处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值