BACK按键流程

来源:互联网 发布:淘宝怎么交保证金 编辑:程序博客网 时间:2024/06/03 21:37

事件被派发到View层次结构的根节点DecorView开始分析,这里我们先来看看DecorView#dispatchKeyEvent方法,代码如下:

@Override

public boolean dispatchKeyEvent(KeyEvent event) {

final int keyCode = event.getKeyCode();

final int action = event.getAction();

final boolean isDown = action == KeyEvent.ACTION_DOWN; 

/// 1. 第一次down事件的时候,处理panel的快捷键

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)) { returntrue; }

}

/// 2. 这里是我们本文的重点,当window没destroy且其Callback非空的话,交给其Callback处理

if (!isDestroyed()) {

// Activity、Dialog都是Callback接口的实现

final Callback cb = getCallback();

// mFeatureId < 0 表示是application的DecorView,比如Activity、Dialog

final boolean handled = cb != null && mFeatureId < 0 ?cb.dispatchKeyEvent(event) //派发给callback的方法 : super.dispatchKeyEvent(event);

// 否则直接派发到ViewGroup#dispatchKeyEvent(View层次结构)

if (handled) {

return true;

// 如果被上面的步骤处理了则直接返回true,不再往下传递

 }

/// 3. 这是key事件的最后一步,如果到这一步还没处理掉,则派发到PhoneWindow对应的onKeyDown, onKeyUp方法

return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(),event) : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event); }

 

 

frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindow.java

 

@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 ofpanel key: if a panel key is held

                // but not released, try toexecute a shortcut in it.

                if ((mPanelChordingKey > 0)&& (mPanelChordingKey != keyCode)) {

                    boolean handled =dispatchKeyShortcutEvent(event);

                    if (handled) {

                        return true;

                    }

                }

 

                // If a panel is open, performa 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);

       }

Activity层的(callback)dispatchKeyEvent

frameworks\base\core\java\android\app\Activity.java

 

public boolean dispatchKeyEvent(KeyEvent event){

       onUserInteraction();

 

       // Let action bars open menus in response to the menu key prioritizedover

       // the window handling it

       if (event.getKeyCode() == KeyEvent.KEYCODE_MENU &&

                mActionBar != null &&mActionBar.onMenuKeyEvent(event)) {

           return true;

       }

 

       Window win = getWindow();

       if (win.superDispatchKeyEvent(event)){

           return true;

       }

       View decor = mDecor;

       if (decor == null) decor = win.getDecorView();

       return event.dispatch(this, decor != null

                ? decor.getKeyDispatcherState(): null, this);

}

 

调用frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindow.java

public booleansuperDispatchKeyEvent(KeyEvent event) {

            // Give priority to closing actionmodes if applicable.

            if (event.getKeyCode() ==KeyEvent.KEYCODE_BACK) {

                final int action =event.getAction();

                // Back cancels action modesfirst.

                if (mActionMode != null) {

                    if (action ==KeyEvent.ACTION_UP) {

                        mActionMode.finish();

                    }

                    return true;

                }

            }

 

            return super.dispatchKeyEvent(event);

        }

 

Viewgroup层的frameworks\base\core\java\android\view\ ViewGroup.java

 

@Override

   public boolean dispatchKeyEvent(KeyEvent event) {

       if (mInputEventConsistencyVerifier != null) {

           mInputEventConsistencyVerifier.onKeyEvent(event, 1);

       }

 

       if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))

                == (PFLAG_FOCUSED |PFLAG_HAS_BOUNDS)) {

           if (super.dispatchKeyEvent(event)) {

               return true;

           }

       } else if (mFocused != null && (mFocused.mPrivateFlags &PFLAG_HAS_BOUNDS)

                == PFLAG_HAS_BOUNDS) {

           if (mFocused.dispatchKeyEvent(event)) {

                return true;

           }

       }

 

       if (mInputEventConsistencyVerifier != null) {

           mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);

       }

       return false;

}

View层frameworks\base\core\java\android\view\view.java

public boolean dispatchKeyEvent(KeyEventevent) {

        if (mInputEventConsistencyVerifier !=null) {

           mInputEventConsistencyVerifier.onKeyEvent(event, 0);

        }

 

        // Give any attached key listener afirst 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;

    }

 

KeyEvent的dispatch

frameworks\base\core\java\android\view\KeyEvent.java

 

public final boolean dispatch(Callbackreceiver, DispatcherState state,

            Object target) {

       switch (mAction) {

           ...

           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);

           ...

       }

       return false;

}

frameworks\base\core\java\android\view\view.java

 

public boolean onKeyUp(int keyCode,KeyEvent event) {

       if (KeyEvent.isConfirmKey(keyCode)) {

           if ((mViewFlags & ENABLED_MASK) == DISABLED) {

                return true;

           }

           if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) {

               setPressed(false);

 

                if (!mHasPerformedLongPress) {

                    // This is a tap, so removethe longpress check

                    removeLongPressCallback();

                    return performClick();

                }

           }

       }

       return false;

    }

 

 

public void setPressed(boolean pressed) {

       final boolean needsRefresh = pressed != ((mPrivateFlags &PFLAG_PRESSED) == PFLAG_PRESSED);

 

       if (pressed) {

           mPrivateFlags |= PFLAG_PRESSED;

       } else {

           mPrivateFlags &= ~PFLAG_PRESSED;

       }

 

       if (needsRefresh) {

           refreshDrawableState();

       }

       dispatchSetPressed(pressed);

}

 

Activity对应的onKeyDownonKeyUp方法

frameworks\base\core\java\android\app\Dialog.java

 

public boolean onKeyUp(int keyCode,KeyEvent event) {

       if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()

                && !event.isCanceled()){

           onBackPressed();

           return true;

       }

       return false;

    }