Android system server之WindowManagerService按键消息传播流程

主要涉及的文件有:

WindowManagerService.java   frameworks\base\services\java\com\android\server\

PhoneWindow.java                     frameworks\policies\base\phone\com\android\internal\policy\impl

KeyInputQueue.java                   frameworks\base\services\java\com\android\server

com_android_server_KeyInputQueue.cpp    frameworks\base\services\jni

EventHub.cpp                                                       frameworks\base\libs\ui

WindowManagerService.java主要有两个线程,一个负责分发按键的InputDisapath Thread,另一个负责从底层读取按键消息InputDeviceRender Thread。

WindowManagerService.java的成员类KeyQ(),负责获取各种按键设备的状态,它继承于KeyInputQueue类。通过线程InputDeviceRender Thread的readEvent对按键消息不停读取,然后调用KeyQ实例化后的processEvent函数告诉该按键是否应该传给上层。接着WindowManagerService通过InputDisPatch Thread在按键消息队列里取出,并进行分发。

由此可知,InputDisapath线程负责分发,InputDeviceRender线程通过jni方式调用android_server_KeyInputQueue_readEvent(),在这里负责转化C++的按键消息为java的格式,android_server_KeyInputQueue_readEvent在EventHub.cpp中获取按键消息。

具体一些细节代码如下:

WindowManagerService中的KeyQ()类,preporcessEvent函数负责对按键进行预处理, 主要的事件类型包括EV_KEY(按键事件)、EV_REL(相对值,如鼠标移动,报告相对于最后一次位置的偏移)和EV_ABS(绝对值,如触摸屏)。

[java]
view plain
copy
print
?

  1. @Override  
  2. boolean preprocessEvent(InputDevice device, RawInputEvent event) {  
  3.     if (mPolicy.preprocessInputEventTq(event)) {  
  4.         return true;  
  5.     }  
  6.   
  7.     switch (event.type) {  
  8.         case RawInputEvent.EV_KEY: {  
  9.             // XXX begin hack   
  10.             if (DEBUG) {  
  11.                 if (event.keycode == KeyEvent.KEYCODE_G) {  
  12.                     if (event.value != 0) {  
  13.                         // G down   
  14.                         mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);  
  15.                     }  
  16.                     return false;  
  17.                 }  
  18.                 if (event.keycode == KeyEvent.KEYCODE_D) {  
  19.                     if (event.value != 0) {  
  20.                         //dump();   
  21.                     }  
  22.                     return false;  
  23.                 }  
  24.             }  
  25.             // XXX end hack   
  26.   
  27.             boolean screenIsOff = !mPowerManager.isScreenOn();  
  28.             boolean screenIsDim = !mPowerManager.isScreenBright();  
  29.             int actions = mPolicy.interceptKeyTq(event, !screenIsOff);/**********按键预处理********//  
  30.   
  31.             if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {  
  32.                 mPowerManager.goToSleep(event.when);  
  33.             }  
  34.   
  35.             if (screenIsOff) {  
  36.                 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;  
  37.             }  
  38.             if (screenIsDim) {  
  39.                 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;  
  40.             }  
  41.             if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {  
  42.                 mPowerManager.userActivity(event.when, false,  
  43.                         LocalPowerManager.BUTTON_EVENT, false);  
  44.             }  
  45.   
  46.             if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {  
  47.                 if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {  
  48.                     filterQueue(this);  
  49.                     mKeyWaiter.appSwitchComing();  
  50.                 }  
  51.                 return true;  
  52.             } else {  
  53.                 return false;  
  54.             }  
  55.         }  
  56.   
  57.         case RawInputEvent.EV_REL: {  
  58.             boolean screenIsOff = !mPowerManager.isScreenOn();  
  59.             boolean screenIsDim = !mPowerManager.isScreenBright();  
  60.             if (screenIsOff) {  
  61.                 if (!mPolicy.isWakeRelMovementTq(event.deviceId,  
  62.                         device.classes, event)) {  
  63.                     //Slog.i(TAG, “dropping because screenIsOff and !isWakeKey”);   
  64.                     return false;  
  65.                 }  
  66.                 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;  
  67.             }  
  68.             if (screenIsDim) {  
  69.                 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;  
  70.             }  
  71.             return true;  
  72.         }  
  73.   
  74.         case RawInputEvent.EV_ABS: {  
  75.             boolean screenIsOff = !mPowerManager.isScreenOn();  
  76.             boolean screenIsDim = !mPowerManager.isScreenBright();  
  77.             if (screenIsOff) {  
  78.                 if (!mPolicy.isWakeAbsMovementTq(event.deviceId,  
  79.                         device.classes, event)) {  
  80.                     //Slog.i(TAG, “dropping because screenIsOff and !isWakeKey”);   
  81.                     return false;  
  82.                 }  
  83.                 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;  
  84.             }  
  85.             if (screenIsDim) {  
  86.                 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;  
  87.             }  
  88.             return true;  
  89.         }  
  90.   
  91.         default:  
  92.             return true;  
  93.     }  
  94. }  
        @Override
        boolean preprocessEvent(InputDevice device, RawInputEvent event) {
            if (mPolicy.preprocessInputEventTq(event)) {
                return true;
            }

            switch (event.type) {
                case RawInputEvent.EV_KEY: {
                    // XXX begin hack
                    if (DEBUG) {
                        if (event.keycode == KeyEvent.KEYCODE_G) {
                            if (event.value != 0) {
                                // G down
                                mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
                            }
                            return false;
                        }
                        if (event.keycode == KeyEvent.KEYCODE_D) {
                            if (event.value != 0) {
                                //dump();
                            }
                            return false;
                        }
                    }
                    // XXX end hack

                    boolean screenIsOff = !mPowerManager.isScreenOn();
                    boolean screenIsDim = !mPowerManager.isScreenBright();
                    int actions = mPolicy.interceptKeyTq(event, !screenIsOff);/**********按键预处理********//

                    if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {
                        mPowerManager.goToSleep(event.when);
                    }

                    if (screenIsOff) {
                        event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
                    }
                    if (screenIsDim) {
                        event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
                    }
                    if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {
                        mPowerManager.userActivity(event.when, false,
                                LocalPowerManager.BUTTON_EVENT, false);
                    }

                    if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {
                        if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {
                            filterQueue(this);
                            mKeyWaiter.appSwitchComing();
                        }
                        return true;
                    } else {
                        return false;
                    }
                }

                case RawInputEvent.EV_REL: {
                    boolean screenIsOff = !mPowerManager.isScreenOn();
                    boolean screenIsDim = !mPowerManager.isScreenBright();
                    if (screenIsOff) {
                        if (!mPolicy.isWakeRelMovementTq(event.deviceId,
                                device.classes, event)) {
                            //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
                            return false;
                        }
                        event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
                    }
                    if (screenIsDim) {
                        event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
                    }
                    return true;
                }

                case RawInputEvent.EV_ABS: {
                    boolean screenIsOff = !mPowerManager.isScreenOn();
                    boolean screenIsDim = !mPowerManager.isScreenBright();
                    if (screenIsOff) {
                        if (!mPolicy.isWakeAbsMovementTq(event.deviceId,
                                device.classes, event)) {
                            //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
                            return false;
                        }
                        event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
                    }
                    if (screenIsDim) {
                        event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
                    }
                    return true;
                }

                default:
                    return true;
            }
        }

preporcessEvent调用了InterceptKeyTQ

PhoneWindowManager.java中的InterceptKeyTQ判断该按键是否应该送给上层,还是在此层进行截取,如待机休眠唤醒则在此层进行截取。

[java]
view plain
copy
print
?

  1.   /** {@inheritDoc} */  
  /** {@inheritDoc} */

[java]
view plain
copy
print
?

  1. //2.3中名为interceptKeyBeforeQueueing   
  2.     public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) {  
  3.         int result = ACTION_PASS_TO_USER;  
  4.         final boolean isWakeKey = isWakeKeyTq(event);  
  5.         // If screen is off then we treat the case where the keyguard is open but hidden   
  6.         // the same as if it were open and in front.   
  7.         // This will prevent any keys other than the power button from waking the screen   
  8.         // when the keyguard is hidden by another activity.   
  9.         final boolean keyguardActive = (screenIsOn ?  
  10.                                         mKeyguardMediator.isShowingAndNotHidden() :  
  11.                                         mKeyguardMediator.isShowing());  
  12.   
  13.   
  14.         if (false) {  
  15.             Log.d(TAG, “interceptKeyTq event=” + event + ” keycode=” + event.keycode  
  16.                   + ” screenIsOn=” + screenIsOn + ” keyguardActive=” + keyguardActive);  
  17.         }  
  18.   
  19.   
  20.         if (keyguardActive) {  
  21.             if (screenIsOn) {  
  22.                 // when the screen is on, always give the event to the keyguard   
  23.                 result |= ACTION_PASS_TO_USER;  
  24.             } else {  
  25.                 // otherwise, don’t pass it to the user   
  26.                 result &= ~ACTION_PASS_TO_USER;  
  27.   
  28.   
  29.                 final boolean isKeyDown =  
  30.                         (event.type == RawInputEvent.EV_KEY) && (event.value != 0);  
  31.                 if (isWakeKey && isKeyDown) {  
  32.   
  33.   
  34.                     // tell the mediator about a wake key, it may decide to   
  35.                     // turn on the screen depending on whether the key is   
  36.                     // appropriate.   
  37.                     if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode)  
  38.                             && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN  
  39.                                 || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {  
  40.                         // when keyguard is showing and screen off, we need   
  41.                         // to handle the volume key for calls and  music here   
  42.                         if (isInCall()) {  
  43.                             handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);  
  44.                         } else if (isMusicActive()) {  
  45.                             handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode);  
  46.                         }  
  47.                     }  
  48.                 }  
  49.             }  
  50.         } else if (!screenIsOn) {  
  51.             // If we are in-call with screen off and keyguard is not showing,   
  52.             // then handle the volume key ourselves.   
  53.             // This is necessary because the phone app will disable the keyguard   
  54.             // when the proximity sensor is in use.   
  55.             if (isInCall() && event.type == RawInputEvent.EV_KEY &&  
  56.                      (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN  
  57.                                 || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {  
  58.                 result &= ~ACTION_PASS_TO_USER;  
  59.                 handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);  
  60.             }  
  61.             if (isWakeKey) {  
  62.                 // a wake key has a sole purpose of waking the device; don’t pass   
  63.                 // it to the user   
  64.                 result |= ACTION_POKE_USER_ACTIVITY;  
  65.                 result &= ~ACTION_PASS_TO_USER;  
  66.             }  
  67.         }  
  68.   
  69.   
  70.         int type = event.type;  
  71.         int code = event.keycode;  
  72.         boolean down = event.value != 0;  
  73.   
  74.   
  75.         if (type == RawInputEvent.EV_KEY) {  
  76.             if (code == KeyEvent.KEYCODE_ENDCALL  
  77.                     || code == KeyEvent.KEYCODE_POWER) {  
  78.                 if (down) {  
  79.                     boolean handled = false;  
  80.                     boolean hungUp = false;  
  81.                     // key repeats are generated by the window manager, and we don’t see them   
  82.                     // here, so unless the driver is doing something it shouldn’t be, we know   
  83.                     // this is the real press event.   
  84.                     ITelephony phoneServ = getPhoneInterface();  
  85.                     if (phoneServ != null) {  
  86.                         try {  
  87.                             if (code == KeyEvent.KEYCODE_ENDCALL) {  
  88.                                 handled = hungUp = phoneServ.endCall();  
  89.                             } else if (code == KeyEvent.KEYCODE_POWER) {  
  90.                                 if (phoneServ.isRinging()) {  
  91.                                     // Pressing Power while there’s a ringing incoming   
  92.                                     // call should silence the ringer.   
  93.                                     phoneServ.silenceRinger();  
  94.                                     handled = true;  
  95.                                 } else if (phoneServ.isOffhook() &&  
  96.                                            ((mIncallPowerBehavior  
  97.                                              & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)  
  98.                                             != 0)) {  
  99.                                     // Otherwise, if “Power button ends call” is enabled,   
  100.                                     // the Power button will hang up any current active call.   
  101.                                     handled = hungUp = phoneServ.endCall();  
  102.                                 }  
  103.                             }  
  104.                         } catch (RemoteException ex) {  
  105.                             Log.w(TAG, “ITelephony threw RemoteException” + ex);  
  106.                         }  
  107.                     } else {  
  108.                         Log.w(TAG, “!!! Unable to find ITelephony interface !!!”);  
  109.                     }  
  110.   
  111.   
  112.                     if (!screenIsOn  
  113.                             || (handled && code != KeyEvent.KEYCODE_POWER)  
  114.                             || (handled && hungUp && code == KeyEvent.KEYCODE_POWER)) {  
  115.                         mShouldTurnOffOnKeyUp = false;  
  116.                     } else {  
  117.                         // only try to turn off the screen if we didn’t already hang up   
  118.                         mShouldTurnOffOnKeyUp = true;  
  119.                         mHandler.postDelayed(mPowerLongPress,  
  120.                                 ViewConfiguration.getGlobalActionKeyTimeout());  
  121.                         result &= ~ACTION_PASS_TO_USER;  
  122.                     }  
  123.                 } else {  
  124.                     mHandler.removeCallbacks(mPowerLongPress);  
  125.                     if (mShouldTurnOffOnKeyUp) {  
  126.                         mShouldTurnOffOnKeyUp = false;  
  127.                         boolean gohome, sleeps;  
  128.                         if (code == KeyEvent.KEYCODE_ENDCALL) {  
  129.                             gohome = (mEndcallBehavior  
  130.                                       & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;  
  131.                             sleeps = (mEndcallBehavior  
  132.                                       & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;  
  133.                         } else {  
  134.                             gohome = false;  
  135.                             sleeps = true;  
  136.                         }  
  137.                         if (keyguardActive  
  138.                                 || (sleeps && !gohome)  
  139.                                 || (gohome && !goHome() && sleeps)) {  
  140.                             // they must already be on the keyguad or home screen,   
  141.                             // go to sleep instead   
  142.                             Log.d(TAG, “I’m tired mEndcallBehavior=0x”  
  143.                                     + Integer.toHexString(mEndcallBehavior));  
  144.                             result &= ~ACTION_POKE_USER_ACTIVITY;  
  145.                             result |= ACTION_GO_TO_SLEEP;  
  146.                         }  
  147.                         result &= ~ACTION_PASS_TO_USER;  
  148.                     }  
  149.                 }  
  150.             } else if (isMediaKey(code)) {  
  151.                 // This key needs to be handled even if the screen is off.   
  152.                 // If others need to be handled while it’s off, this is a reasonable   
  153.                 // pattern to follow.   
  154.                 if ((result & ACTION_PASS_TO_USER) == 0) {  
  155.                     // Only do this if we would otherwise not pass it to the user. In that   
  156.                     // case, the PhoneWindow class will do the same thing, except it will   
  157.                     // only do it if the showing app doesn’t process the key on its own.   
  158.                     KeyEvent keyEvent = new KeyEvent(event.when, event.when,  
  159.                             down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,  
  160.                             code, 0);  
  161.                     mBroadcastWakeLock.acquire();  
  162.                     mHandler.post(new PassHeadsetKey(keyEvent));  
  163.                 }  
  164.             } else if (code == KeyEvent.KEYCODE_CALL) {  
  165.                 // If an incoming call is ringing, answer it!   
  166.                 // (We handle this key here, rather than in the InCallScreen, to make   
  167.                 // sure we’ll respond to the key even if the InCallScreen hasn’t come to   
  168.                 // the foreground yet.)   
  169.   
  170.   
  171.                 // We answer the call on the DOWN event, to agree with   
  172.                 // the “fallback” behavior in the InCallScreen.   
  173.                 if (down) {  
  174.                     try {  
  175.                         ITelephony phoneServ = getPhoneInterface();  
  176.                         if (phoneServ != null) {  
  177.                             if (phoneServ.isRinging()) {  
  178.                                 Log.i(TAG, “interceptKeyTq:”  
  179.                                       + ” CALL key-down while ringing: Answer the call!”);  
  180.                                 phoneServ.answerRingingCall();  
  181.   
  182.   
  183.                                 // And *don’t* pass this key thru to the current activity   
  184.                                 // (which is presumably the InCallScreen.)   
  185.                                 result &= ~ACTION_PASS_TO_USER;  
  186.                             }  
  187.                         } else {  
  188.                             Log.w(TAG, “CALL button: Unable to find ITelephony interface”);  
  189.                         }  
  190.                     } catch (RemoteException ex) {  
  191.                         Log.w(TAG, “CALL button: RemoteException from getPhoneInterface()”, ex);  
  192.                     }  
  193.                 }  
  194.             } else if ((code == KeyEvent.KEYCODE_VOLUME_UP)  
  195.                        || (code == KeyEvent.KEYCODE_VOLUME_DOWN)) {  
  196.                 // If an incoming call is ringing, either VOLUME key means   
  197.                 // “silence ringer”.  We handle these keys here, rather than   
  198.                 // in the InCallScreen, to make sure we’ll respond to them   
  199.                 // even if the InCallScreen hasn’t come to the foreground yet.   
  200.   
  201.   
  202.                 // Look for the DOWN event here, to agree with the “fallback”   
  203.                 // behavior in the InCallScreen.   
  204.                 if (down) {  
  205.                     try {  
  206.                         ITelephony phoneServ = getPhoneInterface();  
  207.                         if (phoneServ != null) {  
  208.                             if (phoneServ.isRinging()) {  
  209.                                 Log.i(TAG, “interceptKeyTq:”  
  210.                                       + ” VOLUME key-down while ringing: Silence ringer!”);  
  211.                                 // Silence the ringer.  (It’s safe to call this   
  212.                                 // even if the ringer has already been silenced.)   
  213.                                 phoneServ.silenceRinger();  
  214.   
  215.   
  216.                                 // And *don’t* pass this key thru to the current activity   
  217.                                 // (which is probably the InCallScreen.)   
  218.                                 result &= ~ACTION_PASS_TO_USER;  
  219.                             }  
  220.                         } else {  
  221.                             Log.w(TAG, “VOLUME button: Unable to find ITelephony interface”);  
  222.                         }  
  223.                     } catch (RemoteException ex) {  
  224.                         Log.w(TAG, “VOLUME button: RemoteException from getPhoneInterface()”, ex);  
  225.                     }  
  226.                 }  
  227.             }  
  228.         }  
  229.   
  230.   
  231.         return result;  
  232.     }  
//2.3中名为interceptKeyBeforeQueueing
    public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) {
        int result = ACTION_PASS_TO_USER;
        final boolean isWakeKey = isWakeKeyTq(event);
        // If screen is off then we treat the case where the keyguard is open but hidden
        // the same as if it were open and in front.
        // This will prevent any keys other than the power button from waking the screen
        // when the keyguard is hidden by another activity.
        final boolean keyguardActive = (screenIsOn ?
                                        mKeyguardMediator.isShowingAndNotHidden() :
                                        mKeyguardMediator.isShowing());


        if (false) {
            Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode
                  + " screenIsOn=" + screenIsOn + " keyguardActive=" + keyguardActive);
        }


        if (keyguardActive) {
            if (screenIsOn) {
                // when the screen is on, always give the event to the keyguard
                result |= ACTION_PASS_TO_USER;
            } else {
                // otherwise, don't pass it to the user
                result &= ~ACTION_PASS_TO_USER;


                final boolean isKeyDown =
                        (event.type == RawInputEvent.EV_KEY) && (event.value != 0);
                if (isWakeKey && isKeyDown) {


                    // tell the mediator about a wake key, it may decide to
                    // turn on the screen depending on whether the key is
                    // appropriate.
                    if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode)
                            && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
                                || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
                        // when keyguard is showing and screen off, we need
                        // to handle the volume key for calls and  music here
                        if (isInCall()) {
                            handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);
                        } else if (isMusicActive()) {
                            handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode);
                        }
                    }
                }
            }
        } else if (!screenIsOn) {
            // If we are in-call with screen off and keyguard is not showing,
            // then handle the volume key ourselves.
            // This is necessary because the phone app will disable the keyguard
            // when the proximity sensor is in use.
            if (isInCall() && event.type == RawInputEvent.EV_KEY &&
                     (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
                                || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
                result &= ~ACTION_PASS_TO_USER;
                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);
            }
            if (isWakeKey) {
                // a wake key has a sole purpose of waking the device; don't pass
                // it to the user
                result |= ACTION_POKE_USER_ACTIVITY;
                result &= ~ACTION_PASS_TO_USER;
            }
        }


        int type = event.type;
        int code = event.keycode;
        boolean down = event.value != 0;


        if (type == RawInputEvent.EV_KEY) {
            if (code == KeyEvent.KEYCODE_ENDCALL
                    || code == KeyEvent.KEYCODE_POWER) {
                if (down) {
                    boolean handled = false;
                    boolean hungUp = false;
                    // key repeats are generated by the window manager, and we don't see them
                    // here, so unless the driver is doing something it shouldn't be, we know
                    // this is the real press event.
                    ITelephony phoneServ = getPhoneInterface();
                    if (phoneServ != null) {
                        try {
                            if (code == KeyEvent.KEYCODE_ENDCALL) {
                                handled = hungUp = phoneServ.endCall();
                            } else if (code == KeyEvent.KEYCODE_POWER) {
                                if (phoneServ.isRinging()) {
                                    // Pressing Power while there's a ringing incoming
                                    // call should silence the ringer.
                                    phoneServ.silenceRinger();
                                    handled = true;
                                } else if (phoneServ.isOffhook() &&
                                           ((mIncallPowerBehavior
                                             & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)
                                            != 0)) {
                                    // Otherwise, if "Power button ends call" is enabled,
                                    // the Power button will hang up any current active call.
                                    handled = hungUp = phoneServ.endCall();
                                }
                            }
                        } catch (RemoteException ex) {
                            Log.w(TAG, "ITelephony threw RemoteException" + ex);
                        }
                    } else {
                        Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
                    }


                    if (!screenIsOn
                            || (handled && code != KeyEvent.KEYCODE_POWER)
                            || (handled && hungUp && code == KeyEvent.KEYCODE_POWER)) {
                        mShouldTurnOffOnKeyUp = false;
                    } else {
                        // only try to turn off the screen if we didn't already hang up
                        mShouldTurnOffOnKeyUp = true;
                        mHandler.postDelayed(mPowerLongPress,
                                ViewConfiguration.getGlobalActionKeyTimeout());
                        result &= ~ACTION_PASS_TO_USER;
                    }
                } else {
                    mHandler.removeCallbacks(mPowerLongPress);
                    if (mShouldTurnOffOnKeyUp) {
                        mShouldTurnOffOnKeyUp = false;
                        boolean gohome, sleeps;
                        if (code == KeyEvent.KEYCODE_ENDCALL) {
                            gohome = (mEndcallBehavior
                                      & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;
                            sleeps = (mEndcallBehavior
                                      & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;
                        } else {
                            gohome = false;
                            sleeps = true;
                        }
                        if (keyguardActive
                                || (sleeps && !gohome)
                                || (gohome && !goHome() && sleeps)) {
                            // they must already be on the keyguad or home screen,
                            // go to sleep instead
                            Log.d(TAG, "I'm tired mEndcallBehavior=0x"
                                    + Integer.toHexString(mEndcallBehavior));
                            result &= ~ACTION_POKE_USER_ACTIVITY;
                            result |= ACTION_GO_TO_SLEEP;
                        }
                        result &= ~ACTION_PASS_TO_USER;
                    }
                }
            } else if (isMediaKey(code)) {
                // This key needs to be handled even if the screen is off.
                // If others need to be handled while it's off, this is a reasonable
                // pattern to follow.
                if ((result & ACTION_PASS_TO_USER) == 0) {
                    // Only do this if we would otherwise not pass it to the user. In that
                    // case, the PhoneWindow class will do the same thing, except it will
                    // only do it if the showing app doesn't process the key on its own.
                    KeyEvent keyEvent = new KeyEvent(event.when, event.when,
                            down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
                            code, 0);
                    mBroadcastWakeLock.acquire();
                    mHandler.post(new PassHeadsetKey(keyEvent));
                }
            } else if (code == KeyEvent.KEYCODE_CALL) {
                // If an incoming call is ringing, answer it!
                // (We handle this key here, rather than in the InCallScreen, to make
                // sure we'll respond to the key even if the InCallScreen hasn't come to
                // the foreground yet.)


                // We answer the call on the DOWN event, to agree with
                // the "fallback" behavior in the InCallScreen.
                if (down) {
                    try {
                        ITelephony phoneServ = getPhoneInterface();
                        if (phoneServ != null) {
                            if (phoneServ.isRinging()) {
                                Log.i(TAG, "interceptKeyTq:"
                                      + " CALL key-down while ringing: Answer the call!");
                                phoneServ.answerRingingCall();


                                // And *don't* pass this key thru to the current activity
                                // (which is presumably the InCallScreen.)
                                result &= ~ACTION_PASS_TO_USER;
                            }
                        } else {
                            Log.w(TAG, "CALL button: Unable to find ITelephony interface");
                        }
                    } catch (RemoteException ex) {
                        Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
                    }
                }
            } else if ((code == KeyEvent.KEYCODE_VOLUME_UP)
                       || (code == KeyEvent.KEYCODE_VOLUME_DOWN)) {
                // If an incoming call is ringing, either VOLUME key means
                // "silence ringer".  We handle these keys here, rather than
                // in the InCallScreen, to make sure we'll respond to them
                // even if the InCallScreen hasn't come to the foreground yet.


                // Look for the DOWN event here, to agree with the "fallback"
                // behavior in the InCallScreen.
                if (down) {
                    try {
                        ITelephony phoneServ = getPhoneInterface();
                        if (phoneServ != null) {
                            if (phoneServ.isRinging()) {
                                Log.i(TAG, "interceptKeyTq:"
                                      + " VOLUME key-down while ringing: Silence ringer!");
                                // Silence the ringer.  (It's safe to call this
                                // even if the ringer has already been silenced.)
                                phoneServ.silenceRinger();


                                // And *don't* pass this key thru to the current activity
                                // (which is probably the InCallScreen.)
                                result &= ~ACTION_PASS_TO_USER;
                            }
                        } else {
                            Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
                        }
                    } catch (RemoteException ex) {
                        Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
                    }
                }
            }
        }


        return result;
    }

WindowManagerService中的InputDispatcherThread线程process,在里头调用mQueue(KeyQ类)的getEvent函数来获取队列中的消息,处理后分发。

[java]
view plain
copy
print
?

  1. private void process() {  
  2.            android.os.Process.setThreadPriority(  
  3.                    android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);  
  4.   
  5.            // The last key event we saw   
  6.            KeyEvent lastKey = null;  
  7.   
  8.            // Last keydown time for auto-repeating keys   
  9.            long lastKeyTime = SystemClock.uptimeMillis();  
  10.            long nextKeyTime = lastKeyTime+LONG_WAIT;  
  11.            long downTime = 0;  
  12.   
  13.            // How many successive repeats we generated   
  14.            int keyRepeatCount = 0;  
  15.   
  16.            // Need to report that configuration has changed?   
  17.            boolean configChanged = false;  
  18.   
  19.            while (true) {  
  20.                long curTime = SystemClock.uptimeMillis();  
  21.   
  22.                if (DEBUG_INPUT) Slog.v(  
  23.                    TAG, “Waiting for next key: now=” + curTime  
  24.                    + “, repeat @ “ + nextKeyTime);  
  25.   
  26.                // Retrieve next event, waiting only as long as the next   
  27.                // repeat timeout.  If the configuration has changed, then   
  28.                // don’t wait at all — we’ll report the change as soon as   
  29.                // we have processed all events.   
  30.                QueuedEvent ev = mQueue.getEvent(//*****获取队列中的消息***//   
  31.                    (int)((!configChanged && curTime < nextKeyTime)  
  32.                            ? (nextKeyTime-curTime) : 0));  
  33.   
  34.                if (DEBUG_INPUT && ev != null) Slog.v(  
  35.                        TAG, “Event: type=” + ev.classType + ” data=” + ev.event);  
  36.   
  37.                if (MEASURE_LATENCY) {  
  38.                    lt.sample(“2 got event              “, System.nanoTime() – ev.whenNano);  
  39.                }  
  40.   
  41.                if (lastKey != null && !mPolicy.allowKeyRepeat()) {  
  42.                    // cancel key repeat at the request of the policy.   
  43.                    lastKey = null;  
  44.                    downTime = 0;  
  45.                    lastKeyTime = curTime;  
  46.                    nextKeyTime = curTime + LONG_WAIT;  
  47.                }  
  48.                try {  
  49.                    if (ev != null) {  
  50.                        curTime = SystemClock.uptimeMillis();  
  51.                        int eventType;  
  52.                        if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {  
  53.                            eventType = eventType((MotionEvent)ev.event);  
  54.                        } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||  
  55.                                    ev.classType == RawInputEvent.CLASS_TRACKBALL) {  
  56.                            eventType = LocalPowerManager.BUTTON_EVENT;  
  57.                        } else {  
  58.                            eventType = LocalPowerManager.OTHER_EVENT;  
  59.                        }  
  60.                        try {  
  61.                            if ((curTime – mLastBatteryStatsCallTime)  
  62.                                    >= MIN_TIME_BETWEEN_USERACTIVITIES) {  
  63.                                mLastBatteryStatsCallTime = curTime;  
  64.                                mBatteryStats.noteInputEvent();  
  65.                            }  
  66.                        } catch (RemoteException e) {  
  67.                            // Ignore   
  68.                        }  
  69.   
  70.                        if (ev.classType == RawInputEvent.CLASS_CONFIGURATION_CHANGED) {  
  71.                            // do not wake screen in this case   
  72.                        } else if (eventType != TOUCH_EVENT  
  73.                                && eventType != LONG_TOUCH_EVENT  
  74.                                && eventType != CHEEK_EVENT) {  
  75.                            mPowerManager.userActivity(curTime, false,  
  76.                                    eventType, false);  
  77.                        } else if (mLastTouchEventType != eventType  
  78.                                || (curTime – mLastUserActivityCallTime)  
  79.                                >= MIN_TIME_BETWEEN_USERACTIVITIES) {  
  80.                            mLastUserActivityCallTime = curTime;  
  81.                            mLastTouchEventType = eventType;  
  82.                            mPowerManager.userActivity(curTime, false,  
  83.                                    eventType, false);  
  84.                        }  
  85.   
  86.                        switch (ev.classType) {  
  87.                            case RawInputEvent.CLASS_KEYBOARD:  
  88.                                KeyEvent ke = (KeyEvent)ev.event;  
  89.                                if (ke.isDown()) {  
  90.                                    lastKey = ke;  
  91.                                    downTime = curTime;  
  92.                                    keyRepeatCount = 0;  
  93.                                    lastKeyTime = curTime;  
  94.                                    nextKeyTime = lastKeyTime  
  95.                                            + ViewConfiguration.getLongPressTimeout();  
  96.                                    if (DEBUG_INPUT) Slog.v(  
  97.                                        TAG, “Received key down: first repeat @ “  
  98.                                        + nextKeyTime);  
  99.                                } else {  
  100.                                    lastKey = null;  
  101.                                    downTime = 0;  
  102.                                    // Arbitrary long timeout.   
  103.                                    lastKeyTime = curTime;  
  104.                                    nextKeyTime = curTime + LONG_WAIT;  
  105.                                    if (DEBUG_INPUT) Slog.v(  
  106.                                        TAG, “Received key up: ignore repeat @ “  
  107.                                        + nextKeyTime);  
  108.                                }  
  109.                                dispatchKey((KeyEvent)ev.event, 00);  
  110.                                mQueue.recycleEvent(ev);  
  111.                                break;  
  112.                            case RawInputEvent.CLASS_TOUCHSCREEN:  
  113.                                //Slog.i(TAG, “Read next event ” + ev);   
  114.                                dispatchPointer(ev, (MotionEvent)ev.event, 00);  
  115.                                break;  
  116.                            case RawInputEvent.CLASS_TRACKBALL:  
  117.                                dispatchTrackball(ev, (MotionEvent)ev.event, 00);  
  118.                                break;  
  119.                            case RawInputEvent.CLASS_CONFIGURATION_CHANGED:  
  120.                                configChanged = true;  
  121.                                break;  
  122.                            default:  
  123.                                mQueue.recycleEvent(ev);  
  124.                            break;  
  125.                        }  
  126.   
  127.                    } else if (configChanged) {  
  128.                        configChanged = false;  
  129.                        sendNewConfiguration();  
  130.   
  131.                    } else if (lastKey != null) {  
  132.                        curTime = SystemClock.uptimeMillis();  
  133.   
  134.                        // Timeout occurred while key was down.  If it is at or   
  135.                        // past the key repeat time, dispatch the repeat.   
  136.                        if (DEBUG_INPUT) Slog.v(  
  137.                            TAG, “Key timeout: repeat=” + nextKeyTime  
  138.                            + “, now=” + curTime);  
  139.                        if (curTime < nextKeyTime) {  
  140.                            continue;  
  141.                        }  
  142.   
  143.                        lastKeyTime = nextKeyTime;  
  144.                        nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;  
  145.                        keyRepeatCount++;  
  146.                        if (DEBUG_INPUT) Slog.v(  
  147.                            TAG, “Key repeat: count=” + keyRepeatCount  
  148.                            + “, next @ “ + nextKeyTime);  
  149.                        KeyEvent newEvent;  
  150.                        if (downTime != 0 && (downTime  
  151.                                + ViewConfiguration.getLongPressTimeout())  
  152.                                <= curTime) {  
  153.                            newEvent = KeyEvent.changeTimeRepeat(lastKey,  
  154.                                    curTime, keyRepeatCount,  
  155.                                    lastKey.getFlags() | KeyEvent.FLAG_LONG_PRESS);  
  156.                            downTime = 0;  
  157.                        } else {  
  158.                            newEvent = KeyEvent.changeTimeRepeat(lastKey,  
  159.                                    curTime, keyRepeatCount);  
  160.                        }  
  161.                        dispatchKey(newEvent, 00);  
  162.   
  163.                    } else {  
  164.                        curTime = SystemClock.uptimeMillis();  
  165.   
  166.                        lastKeyTime = curTime;  
  167.                        nextKeyTime = curTime + LONG_WAIT;  
  168.                    }  
  169.   
  170.                } catch (Exception e) {  
  171.                    Slog.e(TAG,  
  172.                        “Input thread received uncaught exception: “ + e, e);  
  173.                }  
  174.            }  
  175.        }  
  176.    }  
 private void process() {
            android.os.Process.setThreadPriority(
                    android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);

            // The last key event we saw
            KeyEvent lastKey = null;

            // Last keydown time for auto-repeating keys
            long lastKeyTime = SystemClock.uptimeMillis();
            long nextKeyTime = lastKeyTime+LONG_WAIT;
            long downTime = 0;

            // How many successive repeats we generated
            int keyRepeatCount = 0;

            // Need to report that configuration has changed?
            boolean configChanged = false;

            while (true) {
                long curTime = SystemClock.uptimeMillis();

                if (DEBUG_INPUT) Slog.v(
                    TAG, "Waiting for next key: now=" + curTime
                    + ", repeat @ " + nextKeyTime);

                // Retrieve next event, waiting only as long as the next
                // repeat timeout.  If the configuration has changed, then
                // don't wait at all -- we'll report the change as soon as
                // we have processed all events.
                QueuedEvent ev = mQueue.getEvent(//*****获取队列中的消息***//
                    (int)((!configChanged && curTime < nextKeyTime)
                            ? (nextKeyTime-curTime) : 0));

                if (DEBUG_INPUT && ev != null) Slog.v(
                        TAG, "Event: type=" + ev.classType + " data=" + ev.event);

                if (MEASURE_LATENCY) {
                    lt.sample("2 got event              ", System.nanoTime() - ev.whenNano);
                }

                if (lastKey != null && !mPolicy.allowKeyRepeat()) {
                    // cancel key repeat at the request of the policy.
                    lastKey = null;
                    downTime = 0;
                    lastKeyTime = curTime;
                    nextKeyTime = curTime + LONG_WAIT;
                }
                try {
                    if (ev != null) {
                        curTime = SystemClock.uptimeMillis();
                        int eventType;
                        if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
                            eventType = eventType((MotionEvent)ev.event);
                        } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
                                    ev.classType == RawInputEvent.CLASS_TRACKBALL) {
                            eventType = LocalPowerManager.BUTTON_EVENT;
                        } else {
                            eventType = LocalPowerManager.OTHER_EVENT;
                        }
                        try {
                            if ((curTime - mLastBatteryStatsCallTime)
                                    >= MIN_TIME_BETWEEN_USERACTIVITIES) {
                                mLastBatteryStatsCallTime = curTime;
                                mBatteryStats.noteInputEvent();
                            }
                        } catch (RemoteException e) {
                            // Ignore
                        }

                        if (ev.classType == RawInputEvent.CLASS_CONFIGURATION_CHANGED) {
                            // do not wake screen in this case
                        } else if (eventType != TOUCH_EVENT
                                && eventType != LONG_TOUCH_EVENT
                                && eventType != CHEEK_EVENT) {
                            mPowerManager.userActivity(curTime, false,
                                    eventType, false);
                        } else if (mLastTouchEventType != eventType
                                || (curTime - mLastUserActivityCallTime)
                                >= MIN_TIME_BETWEEN_USERACTIVITIES) {
                            mLastUserActivityCallTime = curTime;
                            mLastTouchEventType = eventType;
                            mPowerManager.userActivity(curTime, false,
                                    eventType, false);
                        }

                        switch (ev.classType) {
                            case RawInputEvent.CLASS_KEYBOARD:
                                KeyEvent ke = (KeyEvent)ev.event;
                                if (ke.isDown()) {
                                    lastKey = ke;
                                    downTime = curTime;
                                    keyRepeatCount = 0;
                                    lastKeyTime = curTime;
                                    nextKeyTime = lastKeyTime
                                            + ViewConfiguration.getLongPressTimeout();
                                    if (DEBUG_INPUT) Slog.v(
                                        TAG, "Received key down: first repeat @ "
                                        + nextKeyTime);
                                } else {
                                    lastKey = null;
                                    downTime = 0;
                                    // Arbitrary long timeout.
                                    lastKeyTime = curTime;
                                    nextKeyTime = curTime + LONG_WAIT;
                                    if (DEBUG_INPUT) Slog.v(
                                        TAG, "Received key up: ignore repeat @ "
                                        + nextKeyTime);
                                }
                                dispatchKey((KeyEvent)ev.event, 0, 0);
                                mQueue.recycleEvent(ev);
                                break;
                            case RawInputEvent.CLASS_TOUCHSCREEN:
                                //Slog.i(TAG, "Read next event " + ev);
                                dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
                                break;
                            case RawInputEvent.CLASS_TRACKBALL:
                                dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
                                break;
                            case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
                                configChanged = true;
                                break;
                            default:
                                mQueue.recycleEvent(ev);
                            break;
                        }

                    } else if (configChanged) {
                        configChanged = false;
                        sendNewConfiguration();

                    } else if (lastKey != null) {
                        curTime = SystemClock.uptimeMillis();

                        // Timeout occurred while key was down.  If it is at or
                        // past the key repeat time, dispatch the repeat.
                        if (DEBUG_INPUT) Slog.v(
                            TAG, "Key timeout: repeat=" + nextKeyTime
                            + ", now=" + curTime);
                        if (curTime < nextKeyTime) {
                            continue;
                        }

                        lastKeyTime = nextKeyTime;
                        nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
                        keyRepeatCount++;
                        if (DEBUG_INPUT) Slog.v(
                            TAG, "Key repeat: count=" + keyRepeatCount
                            + ", next @ " + nextKeyTime);
                        KeyEvent newEvent;
                        if (downTime != 0 && (downTime
                                + ViewConfiguration.getLongPressTimeout())
                                <= curTime) {
                            newEvent = KeyEvent.changeTimeRepeat(lastKey,
                                    curTime, keyRepeatCount,
                                    lastKey.getFlags() | KeyEvent.FLAG_LONG_PRESS);
                            downTime = 0;
                        } else {
                            newEvent = KeyEvent.changeTimeRepeat(lastKey,
                                    curTime, keyRepeatCount);
                        }
                        dispatchKey(newEvent, 0, 0);

                    } else {
                        curTime = SystemClock.uptimeMillis();

                        lastKeyTime = curTime;
                        nextKeyTime = curTime + LONG_WAIT;
                    }

                } catch (Exception e) {
                    Slog.e(TAG,
                        "Input thread received uncaught exception: " + e, e);
                }
            }
        }
    }

个人水平有限,有错误欢迎指出,谢谢。

补充:

1、生成

存在这样一个线程,它不断地从driver读取Event,并把它放到RawEvent队列中。这个队列中的RawEvent既有按键,也有触摸、轨迹球等事件。

RawEvent队列中的每个RawEvent最后都会通过一系列转化,最终变为KeyEvent被发送给另外一个线程,即输入线程,也就是一个Activity的主线程。

2、传递

KeyEvent传递过程主要可以划分为三步:过滤器、View树、Activity

过滤器部分主要对应着PhoneWindowManager.java中的interceptKeyTq和interceptKeyTi这两个方法。它们的代码可以在frameworks/base/policy/base/phone/com/Android/internal/policy/impl/PhoneWindowManager.java中看到。

这两个过滤器最大的不同就是interceptKeyTq用于RawEvent,而interceptKeyTi用于KeyEvent。

在一个没有实体键盘的机器上,Power键会被interceptKeyTq这个过滤器吃掉用来调用关机对话框或者使机器休眠。而Home键会被interceptKeyTi这个过滤器吃掉,用来把当前Activity切换到后台并把桌面程序切换到前台。所以,应用程序在View和Activity的onKeyDown/Up中是监听不到这两个按键的。除了这两个键以外的按键,都有机会继续前进。接下来,KeyEvent会先经过interceptKeyTi过滤器,如果这个过滤器不吃掉的话,就会继续前进,进入View树,如果没有被哪个View吃掉的话,最后进入到Activity的onKeyDown/Up方法中。

当一个KeyEvent经过上面的过程还没有被吃掉的话,系统就会利用它做一些定制的功能。比如音量键被系统用来调整声音,多媒体按键用来控制媒体播放,搜索键用来快速打开搜索功能,返回键用来退出当前Activity等

    原文作者:Jack_Zhou888
    原文地址: https://blog.csdn.net/qq258711519/article/details/7845960
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞