zoukankan      html  css  js  c++  java
  • Android 中keyEvent的消息处理(转) -- view部分

    1. ViewRootImpl.deliverKeyEvent(QueuedInputEvent q)

          1. 如果mView为空或者mAdded为false,就直接调用finishInputEvent。

          2. mView.dispatchKeyEventPreIme(event), 在传递给IME之前做一些预处理。因为对于View来说,如果有输入窗口存在的话,会先将按键消息派发到输入窗口,只有当输入窗口没有处理这个事件,才会派发到真正的视图。因此如果想要在输入法截取事件前处理该消息,则可以重载这个方法去处理一些特定的按键消息。

          3. 如果有IME窗口存在,就把这个传递给IME进行处理。imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback);

          4. deliverKeyEventPostIme(q);  将消息派发给真正的视图。

    1. private void deliverKeyEvent(QueuedInputEvent q) {  
    2.     final KeyEvent event = (KeyEvent)q.mEvent;  
    3.     if (mInputEventConsistencyVerifier != null) {  
    4.         mInputEventConsistencyVerifier.onKeyEvent(event, 0);  
    5.     }  
    6.   
    7.     if ((q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {  
    8.         // If there is no view, then the event will not be handled.   
    9.         if (mView == null || !mAdded) {  
    10.             finishInputEvent(q, false);  
    11.             return;  
    12.         }  
    13.   
    14.         if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView);  
    15.   
    16.         // Perform predispatching before the IME.   
    17.         if (mView.dispatchKeyEventPreIme(event)) {  
    18.             finishInputEvent(q, true);  
    19.             return;  
    20.         }  
    21.   
    22.         // Dispatch to the IME before propagating down the view hierarchy.   
    23.         // The IME will eventually call back into handleImeFinishedEvent.   
    24.         if (mLastWasImTarget) {  
    25.             InputMethodManager imm = InputMethodManager.peekInstance();  
    26.             if (imm != null) {  
    27.                 final int seq = event.getSequenceNumber();  
    28.                 if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="  
    29.                         + seq + " event=" + event);  
    30.                 imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback);  
    31.                 return;  
    32.             }  
    33.         }  
    34.     }  
    35.   
    36.     // Not dispatching to IME, continue with post IME actions.   
    37.     deliverKeyEventPostIme(q);  
    38. }  
        private void deliverKeyEvent(QueuedInputEvent q) {
            final KeyEvent event = (KeyEvent)q.mEvent;
            if (mInputEventConsistencyVerifier != null) {
                mInputEventConsistencyVerifier.onKeyEvent(event, 0);
            }
    
            if ((q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
                // If there is no view, then the event will not be handled.
                if (mView == null || !mAdded) {
                    finishInputEvent(q, false);
                    return;
                }
    
                if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView);
    
                // Perform predispatching before the IME.
                if (mView.dispatchKeyEventPreIme(event)) {
                    finishInputEvent(q, true);
                    return;
                }
    
                // Dispatch to the IME before propagating down the view hierarchy.
                // The IME will eventually call back into handleImeFinishedEvent.
                if (mLastWasImTarget) {
                    InputMethodManager imm = InputMethodManager.peekInstance();
                    if (imm != null) {
                        final int seq = event.getSequenceNumber();
                        if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
                                + seq + " event=" + event);
                        imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback);
                        return;
                    }
                }
            }
    
            // Not dispatching to IME, continue with post IME actions.
            deliverKeyEventPostIme(q);
        }
    


    1.2  ViewRootImpl.deliverKeyEventPostIme(q);

             1. mView.dispatchKeyEvent(event);  将事件派发到View视图。因为mView就是一个DecorView,所以就是调用DecorView的dispatchKeyEvent的方法。

    1. private void deliverKeyEventPostIme(QueuedInputEvent q) {  
    2.     final KeyEvent event = (KeyEvent)q.mEvent;  
    3.   
    4.     ... ...  
    5.     // If the key's purpose is to exit touch mode then we consume it and consider it handled.   
    6.     if (checkForLeavingTouchModeAndConsume(event)) {  
    7.         finishInputEvent(q, true);  
    8.         return;  
    9.     }  
    10.   
    11.     // Make sure the fallback event policy sees all keys that will be delivered to the   
    12.     // view hierarchy.   
    13.     mFallbackEventHandler.preDispatchKeyEvent(event);  
    14.   
    15.     // Deliver the key to the view hierarchy.   
    16.     if (mView.dispatchKeyEvent(event)) {  
    17.         finishInputEvent(q, true);  
    18.         return;  
    19.     }  
    20.   
    21.     // If the Control modifier is held, try to interpret the key as a shortcut.   
    22.     if (event.getAction() == KeyEvent.ACTION_DOWN  
    23.             && event.isCtrlPressed()  
    24.             && event.getRepeatCount() == 0  
    25.             && !KeyEvent.isModifierKey(event.getKeyCode())) {  
    26.         if (mView.dispatchKeyShortcutEvent(event)) {  
    27.             finishInputEvent(q, true);  
    28.             return;  
    29.         }  
    30.     }  
    31.   
    32.     // Apply the fallback event policy.   
    33.     if (mFallbackEventHandler.dispatchKeyEvent(event)) {  
    34.         finishInputEvent(q, true);  
    35.         return;  
    36.     }  
    37.   
    38.     // Handle automatic focus changes.   
    39.     if (event.getAction() == KeyEvent.ACTION_DOWN) {  
    40.         int direction = 0;  
    41.         switch (event.getKeyCode()) {  
    42.             case KeyEvent.KEYCODE_DPAD_LEFT:  
    43.                 if (event.hasNoModifiers()) {  
    44.                     direction = View.FOCUS_LEFT;  
    45.                 }  
    46.                 break;  
    47.             case KeyEvent.KEYCODE_DPAD_RIGHT:  
    48.                 if (event.hasNoModifiers()) {  
    49.                     direction = View.FOCUS_RIGHT;  
    50.                 }  
    51.                 break;  
    52.             case KeyEvent.KEYCODE_DPAD_UP:  
    53.                 if (event.hasNoModifiers()) {  
    54.                     direction = View.FOCUS_UP;  
    55.                 }  
    56.                 break;  
    57.             case KeyEvent.KEYCODE_DPAD_DOWN:  
    58.                 if (event.hasNoModifiers()) {  
    59.                     direction = View.FOCUS_DOWN;  
    60.                 }  
    61.                 break;  
    62.             case KeyEvent.KEYCODE_TAB:  
    63.                 if (event.hasNoModifiers()) {  
    64.                     direction = View.FOCUS_FORWARD;  
    65.                 } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {  
    66.                     direction = View.FOCUS_BACKWARD;  
    67.                 }  
    68.                 break;  
    69.         }  
    70.         if (direction != 0) {  
    71.             View focused = mView.findFocus();  
    72.             if (focused != null) {  
    73.                 View v = focused.focusSearch(direction);  
    74.                 if (v != null && v != focused) {  
    75.                     // do the math the get the interesting rect   
    76.                     // of previous focused into the coord system of   
    77.                     // newly focused view   
    78.                     focused.getFocusedRect(mTempRect);  
    79.                     if (mView instanceof ViewGroup) {  
    80.                         ((ViewGroup) mView).offsetDescendantRectToMyCoords(  
    81.                                 focused, mTempRect);  
    82.                         ((ViewGroup) mView).offsetRectIntoDescendantCoords(  
    83.                                 v, mTempRect);  
    84.                     }  
    85.                     if (v.requestFocus(direction, mTempRect)) {  
    86.                         playSoundEffect(SoundEffectConstants  
    87.                                 .getContantForFocusDirection(direction));  
    88.                         finishInputEvent(q, true);  
    89.                         return;  
    90.                     }  
    91.                 }  
    92.   
    93.                 // Give the focused view a last chance to handle the dpad key.   
    94.                 if (mView.dispatchUnhandledMove(focused, direction)) {  
    95.                     finishInputEvent(q, true);  
    96.                     return;  
    97.                 }  
    98.             }  
    99.         }  
    100.     }  
    101.   
    102.     // Key was unhandled.   
    103.     finishInputEvent(q, false);  
    104. }  
        private void deliverKeyEventPostIme(QueuedInputEvent q) {
            final KeyEvent event = (KeyEvent)q.mEvent;
    
            ... ...
            // If the key's purpose is to exit touch mode then we consume it and consider it handled.
            if (checkForLeavingTouchModeAndConsume(event)) {
                finishInputEvent(q, true);
                return;
            }
    
            // Make sure the fallback event policy sees all keys that will be delivered to the
            // view hierarchy.
            mFallbackEventHandler.preDispatchKeyEvent(event);
    
            // Deliver the key to the view hierarchy.
            if (mView.dispatchKeyEvent(event)) {
                finishInputEvent(q, true);
                return;
            }
    
            // If the Control modifier is held, try to interpret the key as a shortcut.
            if (event.getAction() == KeyEvent.ACTION_DOWN
                    && event.isCtrlPressed()
                    && event.getRepeatCount() == 0
                    && !KeyEvent.isModifierKey(event.getKeyCode())) {
                if (mView.dispatchKeyShortcutEvent(event)) {
                    finishInputEvent(q, true);
                    return;
                }
            }
    
            // Apply the fallback event policy.
            if (mFallbackEventHandler.dispatchKeyEvent(event)) {
                finishInputEvent(q, true);
                return;
            }
    
            // Handle automatic focus changes.
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                int direction = 0;
                switch (event.getKeyCode()) {
                    case KeyEvent.KEYCODE_DPAD_LEFT:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_LEFT;
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_RIGHT:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_RIGHT;
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_UP:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_UP;
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_DOWN:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_DOWN;
                        }
                        break;
                    case KeyEvent.KEYCODE_TAB:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_FORWARD;
                        } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
                            direction = View.FOCUS_BACKWARD;
                        }
                        break;
                }
                if (direction != 0) {
                    View focused = mView.findFocus();
                    if (focused != null) {
                        View v = focused.focusSearch(direction);
                        if (v != null && v != focused) {
                            // do the math the get the interesting rect
                            // of previous focused into the coord system of
                            // newly focused view
                            focused.getFocusedRect(mTempRect);
                            if (mView instanceof ViewGroup) {
                                ((ViewGroup) mView).offsetDescendantRectToMyCoords(
                                        focused, mTempRect);
                                ((ViewGroup) mView).offsetRectIntoDescendantCoords(
                                        v, mTempRect);
                            }
                            if (v.requestFocus(direction, mTempRect)) {
                                playSoundEffect(SoundEffectConstants
                                        .getContantForFocusDirection(direction));
                                finishInputEvent(q, true);
                                return;
                            }
                        }
    
                        // Give the focused view a last chance to handle the dpad key.
                        if (mView.dispatchUnhandledMove(focused, direction)) {
                            finishInputEvent(q, true);
                            return;
                        }
                    }
                }
            }
    
            // Key was unhandled.
            finishInputEvent(q, false);
        }
    


    1.2.1 DecorView.dispatchKeyEvent(KeyEvent event)

         1. 如果是Down事件, 首先会判断是不是Shortcut事件也就是快捷键按钮或者特殊事件,如果是就会调用dispatchKeyShortcutEvent和performPanelShortcut进行一些处理然后返回。

         2. 如果不是快捷键按钮,就调用Callback Activity的cb.dispatchKeyEvent(event)去处理。Activity的dispatchKeyEvent中其实也还是去调用PhoneWindow中的superDispatchKeyEvent, PhoneWindow最终还是调用mDecor.superDispatchKeyEvent(event);

    1. @Override  
    2. public boolean dispatchKeyEvent(KeyEvent event) {  
    3.     final int keyCode = event.getKeyCode();  
    4.     final int action = event.getAction();  
    5.     final boolean isDown = action == KeyEvent.ACTION_DOWN;  
    6.   
    7.     if (isDown && (event.getRepeatCount() == 0)) {  
    8.         // First handle chording of panel key: if a panel key is held   
    9.         // but not released, try to execute a shortcut in it.   
    10.         if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) {  
    11.             boolean handled = dispatchKeyShortcutEvent(event);  
    12.             if (handled) {  
    13.                 return true;  
    14.             }  
    15.         }  
    16.   
    17.         // If a panel is open, perform a shortcut on it without the   
    18.         // chorded panel key   
    19.         if ((mPreparedPanel != null) && mPreparedPanel.isOpen) {  
    20.             if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) {  
    21.                 return true;  
    22.             }  
    23.         }  
    24.     }  
    25.   
    26.     if (!isDestroyed()) {  
    27.         final Callback cb = getCallback();  
    28.         final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)  
    29.                 : super.dispatchKeyEvent(event);  
    30.         if (handled) {  
    31.             return true;  
    32.         }  
    33.     }  
    34.   
    35.     return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)  
    36.             : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);  
    37. }  
            @Override
            public boolean dispatchKeyEvent(KeyEvent event) {
                final int keyCode = event.getKeyCode();
                final int action = event.getAction();
                final boolean isDown = action == KeyEvent.ACTION_DOWN;
    
                if (isDown && (event.getRepeatCount() == 0)) {
                    // First handle chording of panel key: if a panel key is held
                    // but not released, try to execute a shortcut in it.
                    if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) {
                        boolean handled = dispatchKeyShortcutEvent(event);
                        if (handled) {
                            return true;
                        }
                    }
    
                    // If a panel is open, perform a shortcut on it without the
                    // chorded panel key
                    if ((mPreparedPanel != null) && mPreparedPanel.isOpen) {
                        if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) {
                            return true;
                        }
                    }
                }
    
                if (!isDestroyed()) {
                    final Callback cb = getCallback();
                    final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
                            : super.dispatchKeyEvent(event);
                    if (handled) {
                        return true;
                    }
                }
    
                return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
                        : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
            }
    


    1.2.1.2 DecorView.mDecor.superDispatchKeyEvent(event);

               1. 调用父类的dispatchKeyEvent。

    1. public boolean superDispatchKeyEvent(KeyEvent event) {  
    2.      if (super.dispatchKeyEvent(event)) {  
    3.          return true;  
    4.      }  
    5.   
    6.      // Not handled by the view hierarchy, does the action bar want it   
    7.      // to cancel out of something special?   
    8.      if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {  
    9.          final int action = event.getAction();  
    10.          // Back cancels action modes first.   
    11.          if (mActionMode != null) {  
    12.              if (action == KeyEvent.ACTION_UP) {  
    13.                  mActionMode.finish();  
    14.              }  
    15.              return true;  
    16.          }  
    17.   
    18.          // Next collapse any expanded action views.   
    19.          if (mActionBar != null && mActionBar.hasExpandedActionView()) {  
    20.              if (action == KeyEvent.ACTION_UP) {  
    21.                  mActionBar.collapseActionView();  
    22.              }  
    23.              return true;  
    24.          }  
    25.      }  
    26.   
    27.      return false;  
    28.  }  
           public boolean superDispatchKeyEvent(KeyEvent event) {
                if (super.dispatchKeyEvent(event)) {
                    return true;
                }
    
                // Not handled by the view hierarchy, does the action bar want it
                // to cancel out of something special?
                if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                    final int action = event.getAction();
                    // Back cancels action modes first.
                    if (mActionMode != null) {
                        if (action == KeyEvent.ACTION_UP) {
                            mActionMode.finish();
                        }
                        return true;
                    }
    
                    // Next collapse any expanded action views.
                    if (mActionBar != null && mActionBar.hasExpandedActionView()) {
                        if (action == KeyEvent.ACTION_UP) {
                            mActionBar.collapseActionView();
                        }
                        return true;
                    }
                }
    
                return false;
            }



    1.2.1.2.1 ViewGroup.dispatchKeyEvent(KeyEvent event)

            1. mPrivateFlags 是在View中定义的,标志当前View的属性。 这里吧的FOCUSED 和HAS_BOUNDS表示当前的View是否是focused和有bounds的。一般的View和ViewGroup都会有HAS_BOUNDS, 而mFocused记录这当前ViewGroup中处于focus的View。

                 例如:如果A包含B,B又包含C,如果C是一个View,C的mPrivateFlags就是 FOCUSED | HAS_BOUNDS那么B的mPrivateFlags就是FOCUSED,mFocused就是C,同理A的mPrivateFlags也是FOCUSED,mFocused就是B。

            2. 所以一般情况下,ViewGroup通过mFocused.dispatchKeyEvent()递归把Event传到View。

    1. public boolean dispatchKeyEvent(KeyEvent event) {  
    2.     if (mInputEventConsistencyVerifier != null) {  
    3.         mInputEventConsistencyVerifier.onKeyEvent(event, 1);  
    4.     }  
    5.   
    6.     if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {  
    7.         if (super.dispatchKeyEvent(event)) {  
    8.             return true;  
    9.         }  
    10.     } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {  
    11.         if (mFocused.dispatchKeyEvent(event)) {  
    12.             return true;  
    13.         }  
    14.     }  
    15.   
    16.     if (mInputEventConsistencyVerifier != null) {  
    17.         mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);  
    18.     }  
    19.     return false;  
    20. }  
        public boolean dispatchKeyEvent(KeyEvent event) {
            if (mInputEventConsistencyVerifier != null) {
                mInputEventConsistencyVerifier.onKeyEvent(event, 1);
            }
    
            if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
                if (super.dispatchKeyEvent(event)) {
                    return true;
                }
            } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
                if (mFocused.dispatchKeyEvent(event)) {
                    return true;
                }
            }
    
            if (mInputEventConsistencyVerifier != null) {
                mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
            }
            return false;
        }
    


    1.2.1.2.1.2 View.dispatchKeyEvent()

                如果mFocused是ViewGroup那么还是调用1.2.1.2.1;如果是View,那么就调用View的dispatchKeyEvent。

                1. 如果有注册Listener,就直接调用Listener的onKey去相应,然后返回。

                2. 如果没有注册Listener,就调用KeyEvent.dispatch去做最后的处理

    1. public boolean dispatchKeyEvent(KeyEvent event) {  
    2.     if (mInputEventConsistencyVerifier != null) {  
    3.         mInputEventConsistencyVerifier.onKeyEvent(event, 0);  
    4.     }  
    5.   
    6.     // Give any attached key listener a first crack at the event.   
    7.     //noinspection SimplifiableIfStatement   
    8.     ListenerInfo li = mListenerInfo;  
    9.     if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED  
    10.             && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {  
    11.         return true;  
    12.     }  
    13.   
    14.     if (event.dispatch(this, mAttachInfo != null  
    15.             ? mAttachInfo.mKeyDispatchState : nullthis)) {  
    16.         return true;  
    17.     }  
    18.   
    19.     if (mInputEventConsistencyVerifier != null) {  
    20.         mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);  
    21.     }  
    22.     return false;  
    23. }  
        public boolean dispatchKeyEvent(KeyEvent event) {
            if (mInputEventConsistencyVerifier != null) {
                mInputEventConsistencyVerifier.onKeyEvent(event, 0);
            }
    
            // Give any attached key listener a first crack at the event.
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
                return true;
            }
    
            if (event.dispatch(this, mAttachInfo != null
                    ? mAttachInfo.mKeyDispatchState : null, this)) {
                return true;
            }
    
            if (mInputEventConsistencyVerifier != null) {
                mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
            }
            return false;
        }
    


    1.2.1.2.1.2.2 KeyEvent.dispatch

            1. KeyEvent.dispatch会根据Action的类型调用receiver的对应的onXXX函数去处理。(receiver通常都是View)

            2. 如果所有的View都没有处理这个KeyEvent,那么会最终通过KeyEvent调用Activity的onXXX函数。

    1. public final boolean dispatch(Callback receiver, DispatcherState state,  
    2.         Object target) {  
    3.     switch (mAction) {  
    4.         case ACTION_DOWN: {  
    5.             mFlags &= ~FLAG_START_TRACKING;  
    6.             if (DEBUG) Log.v(TAG, "Key down to " + target + " in " + state  
    7.                     + ": " + this);  
    8.             boolean res = receiver.onKeyDown(mKeyCode, this);  
    9.             if (state != null) {  
    10.                 if (res && mRepeatCount == 0 && (mFlags&FLAG_START_TRACKING) != 0) {  
    11.                     if (DEBUG) Log.v(TAG, "  Start tracking!");  
    12.                     state.startTracking(this, target);  
    13.                 } else if (isLongPress() && state.isTracking(this)) {  
    14.                     try {  
    15.                         if (receiver.onKeyLongPress(mKeyCode, this)) {  
    16.                             if (DEBUG) Log.v(TAG, "  Clear from long press!");  
    17.                             state.performedLongPress(this);  
    18.                             res = true;  
    19.                         }  
    20.                     } catch (AbstractMethodError e) {  
    21.                     }  
    22.                 }  
    23.             }  
    24.             return res;  
    25.         }  
    26.         case ACTION_UP:  
    27.             if (DEBUG) Log.v(TAG, "Key up to " + target + " in " + state  
    28.                     + ": " + this);  
    29.             if (state != null) {  
    30.                 state.handleUpEvent(this);  
    31.             }  
    32.             return receiver.onKeyUp(mKeyCode, this);  
    33.         case ACTION_MULTIPLE:  
    34.             final int count = mRepeatCount;  
    35.             final int code = mKeyCode;  
    36.             if (receiver.onKeyMultiple(code, count, this)) {  
    37.                 return true;  
    38.             }  
    39.             if (code != KeyEvent.KEYCODE_UNKNOWN) {  
    40.                 mAction = ACTION_DOWN;  
    41.                 mRepeatCount = 0;  
    42.                 boolean handled = receiver.onKeyDown(code, this);  
    43.                 if (handled) {  
    44.                     mAction = ACTION_UP;  
    45.                     receiver.onKeyUp(code, this);  
    46.                 }  
    47.                 mAction = ACTION_MULTIPLE;  
    48.                 mRepeatCount = count;  
    49.                 return handled;  
    50.             }  
    51.             return false;  
    52.     }  
    53.     return false;  
    54. }  
        public final boolean dispatch(Callback receiver, DispatcherState state,
                Object target) {
            switch (mAction) {
                case ACTION_DOWN: {
                    mFlags &= ~FLAG_START_TRACKING;
                    if (DEBUG) Log.v(TAG, "Key down to " + target + " in " + state
                            + ": " + this);
                    boolean res = receiver.onKeyDown(mKeyCode, this);
                    if (state != null) {
                        if (res && mRepeatCount == 0 && (mFlags&FLAG_START_TRACKING) != 0) {
                            if (DEBUG) Log.v(TAG, "  Start tracking!");
                            state.startTracking(this, target);
                        } else if (isLongPress() && state.isTracking(this)) {
                            try {
                                if (receiver.onKeyLongPress(mKeyCode, this)) {
                                    if (DEBUG) Log.v(TAG, "  Clear from long press!");
                                    state.performedLongPress(this);
                                    res = true;
                                }
                            } catch (AbstractMethodError e) {
                            }
                        }
                    }
                    return res;
                }
                case ACTION_UP:
                    if (DEBUG) Log.v(TAG, "Key up to " + target + " in " + state
                            + ": " + this);
                    if (state != null) {
                        state.handleUpEvent(this);
                    }
                    return receiver.onKeyUp(mKeyCode, this);
                case ACTION_MULTIPLE:
                    final int count = mRepeatCount;
                    final int code = mKeyCode;
                    if (receiver.onKeyMultiple(code, count, this)) {
                        return true;
                    }
                    if (code != KeyEvent.KEYCODE_UNKNOWN) {
                        mAction = ACTION_DOWN;
                        mRepeatCount = 0;
                        boolean handled = receiver.onKeyDown(code, this);
                        if (handled) {
                            mAction = ACTION_UP;
                            receiver.onKeyUp(code, this);
                        }
                        mAction = ACTION_MULTIPLE;
                        mRepeatCount = count;
                        return handled;
                    }
                    return false;
            }
            return false;
        }
  • 相关阅读:
    基于WPF的UI自动化测试[1] 自动化测试工具
    PSR
    技术型人员如何晋升项目经理
    HyperV 组件架构(1)—总体架构
    从技术到管理:工作转型后角色定位
    Web性能优化方案
    一个项目经理的一些个人体会
    从技术人才到项目管理的跨越
    研发项目经理的管理
    从程序类转向销售类工作,该如何进行?
  • 原文地址:https://www.cnblogs.com/fireflyxml/p/3604427.html
Copyright © 2011-2022 走看看