1. 程式人生 > >Android system server之WindowManagerService按鍵訊息傳播流程

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 plaincopyprint?
  1. @Override
  2. boolean preprocessEvent(InputDevice device, RawInputEvent event) {  
  3. if (mPolicy.preprocessInputEventTq(event)) {  
  4. returntrue;  
  5.     }  
  6. switch (event.type) {  
  7. case RawInputEvent.EV_KEY: {  
  8. // XXX begin hack
  9. if (DEBUG) {  
  10. if (event.keycode == KeyEvent.KEYCODE_G) {  
  11. if (event.value != 0) {  
  12. // G down
  13.                         mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);  
  14.                     }  
  15. returnfalse;  
  16.                 }  
  17. if (event.keycode == KeyEvent.KEYCODE_D) {  
  18. if (event.value != 0) {  
  19. //dump();
  20.                     }  
  21. returnfalse;  
  22.                 }  
  23.             }  
  24. // XXX end hack
  25. boolean screenIsOff = !mPowerManager.isScreenOn();  
  26. boolean screenIsDim = !mPowerManager.isScreenBright();  
  27. int actions = mPolicy.interceptKeyTq(event, !screenIsOff);/**********按鍵預處理********//  
  28. if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {  
  29.                 mPowerManager.goToSleep(event.when);  
  30.             }  
  31. if (screenIsOff) {  
  32.                 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;  
  33.             }  
  34. if (screenIsDim) {  
  35.                 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;  
  36.             }  
  37. if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {  
  38.                 mPowerManager.userActivity(event.when, false,  
  39.                         LocalPowerManager.BUTTON_EVENT, false);  
  40.             }  
  41. if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {  
  42. if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {  
  43.                     filterQueue(this);  
  44.                     mKeyWaiter.appSwitchComing();  
  45.                 }  
  46. returntrue;  
  47.             } else {  
  48. returnfalse;  
  49.             }  
  50.         }  
  51. case RawInputEvent.EV_REL: {  
  52. boolean screenIsOff = !mPowerManager.isScreenOn();  
  53. boolean screenIsDim = !mPowerManager.isScreenBright();  
  54. if (screenIsOff) {  
  55. if (!mPolicy.isWakeRelMovementTq(event.deviceId,  
  56.                         device.classes, event)) {  
  57. //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
  58. returnfalse;  
  59.                 }  
  60.                 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;  
  61.             }  
  62. if (screenIsDim) {  
  63.                 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;  
  64.             }  
  65. returntrue;  
  66.         }  
  67. case RawInputEvent.EV_ABS: {  
  68. boolean screenIsOff = !mPowerManager.isScreenOn();  
  69. boolean screenIsDim = !mPowerManager.isScreenBright();  
  70. if (screenIsOff) {  
  71. if (!mPolicy.isWakeAbsMovementTq(event.deviceId,  
  72.                         device.classes, event)) {  
  73. //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
  74. returnfalse;  
  75.                 }  
  76.                 event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;  
  77.             }  
  78. if (screenIsDim) {  
  79.                 event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;  
  80.             }  
  81. returntrue;  
  82.         }  
  83. default:  
  84. returntrue;  
  85.     }  
  86. }  
        @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 plaincopyprint?
  1. /** {@inheritDoc} */
  /** {@inheritDoc} */
[java] view plaincopyprint?
  1. //2.3中名為interceptKeyBeforeQueueing
  2. publicint interceptKeyTq(RawInputEvent event, boolean screenIsOn) {  
  3. int result = ACTION_PASS_TO_USER;  
  4. finalboolean 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. finalboolean keyguardActive = (screenIsOn ?  
  10.                                         mKeyguardMediator.isShowingAndNotHidden() :  
  11.                                         mKeyguardMediator.isShowing());  
  12. if (false) {  
  13.             Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode  
  14.                   + " screenIsOn=" + screenIsOn + " keyguardActive=" + keyguardActive);  
  15.         }  
  16. if (keyguardActive) {  
  17. if (screenIsOn) {  
  18. // when the screen is on, always give the event to the keyguard
  19.                 result |= ACTION_PASS_TO_USER;  
  20.             } else {  
  21. // otherwise, don't pass it to the user
  22.                 result &= ~ACTION_PASS_TO_USER;  
  23. finalboolean isKeyDown =  
  24.                         (event.type == RawInputEvent.EV_KEY) && (event.value != 0);  
  25. if (isWakeKey && isKeyDown) {  
  26. // tell the mediator about a wake key, it may decide to
  27. // turn on the screen depending on whether the key is
  28. // appropriate.
  29. if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode)  
  30.                             && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN  
  31.                                 || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {  
  32. // when keyguard is showing and screen off, we need
  33. // to handle the volume key for calls and  music here
  34. if (isInCall()) {  
  35.                             handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);  
  36.                         } elseif (isMusicActive()) {  
  37.                             handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode);  
  38.                         }  
  39.                     }  
  40.                 }  
  41.             }  
  42.         } elseif (!screenIsOn) {  
  43. // If we are in-call with screen off and keyguard is not showing,
  44. // then handle the volume key ourselves.
  45. // This is necessary because the phone app will disable the keyguard
  46. // when the proximity sensor is in use.
  47. if (isInCall() && event.type == RawInputEvent.EV_KEY &&  
  48.                      (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN  
  49.                                 || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {  
  50.                 result &= ~ACTION_PASS_TO_USER;  
  51.                 handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);  
  52.             }  
  53. if (isWakeKey) {  
  54. // a wake key has a sole purpose of waking the device; don't pass
  55. // it to the user
  56.                 result |= ACTION_POKE_USER_ACTIVITY;  
  57.                 result &= ~ACTION_PASS_TO_USER;  
  58.             }  
  59.         }  
  60. int type = event.type;  
  61. int code = event.keycode;  
  62. boolean down = event.value != 0;  
  63. if (type == RawInputEvent.EV_KEY) {  
  64. if (code == KeyEvent.KEYCODE_ENDCALL  
  65.                     || code == KeyEvent.KEYCODE_POWER) {  
  66. if (down) {  
  67. boolean handled = false;  
  68. boolean hungUp = false;  
  69. // key repeats are generated by the window manager, and we don't see them
  70. // here, so unless the driver is doing something it shouldn't be, we know
  71. // this is the real press event.
  72.                     ITelephony phoneServ = getPhoneInterface();  
  73. if (phoneServ != null) {  
  74. try {  
  75. if (code == KeyEvent.KEYCODE_ENDCALL) {  
  76.                                 handled = hungUp = phoneServ.endCall();  
  77.                             } elseif (code == KeyEvent.KEYCODE_POWER) {  
  78. if (phoneServ.isRinging()) {  
  79. // Pressing Power while there's a ringing incoming
  80. // call should silence the ringer.
  81.                                     phoneServ.silenceRinger();  
  82.                                     handled = true;  
  83.                                 } elseif (phoneServ.isOffhook() &&  
  84.                                            ((mIncallPowerBehavior  
  85.                                              & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)  
  86.                                             != 0)) {  
  87. // Otherwise, if "Power button ends call" is enabled,
  88. // the Power button will hang up any current active call.
  89.                                     handled = hungUp = phoneServ.endCall();  
  90.                                 }  
  91.                             }  
  92.                         } catch (RemoteException ex) {  
  93.                             Log.w(TAG, "ITelephony threw RemoteException" + ex);  
  94.                         }  
  95.                     } else {  
  96.                         Log.w(TAG, "!!! Unable to find ITelephony interface !!!");  
  97.                     }  
  98. if (!screenIsOn  
  99.                             || (handled && code != KeyEvent.KEYCODE_POWER)  
  100.                             || (handled && hungUp && code == KeyEvent.KEYCODE_POWER)) {  
  101.                         mShouldTurnOffOnKeyUp = false;  
  102.                     } else {  
  103. // only try to turn off the screen if we didn't already hang up
  104.                         mShouldTurnOffOnKeyUp = true;  
  105.                         mHandler.postDelayed(mPowerLongPress,  
  106.                                 ViewConfiguration.getGlobalActionKeyTimeout());  
  107.                         result &= ~ACTION_PASS_TO_USER;  
  108.                     }  
  109.                 } else {  
  110.                     mHandler.removeCallbacks(mPowerLongPress);  
  111. if (mShouldTurnOffOnKeyUp) {  
  112.                         mShouldTurnOffOnKeyUp = false;  
  113. boolean gohome, sleeps;  
  114. if (code == KeyEvent.KEYCODE_ENDCALL) {  
  115.                             gohome = (mEndcallBehavior  
  116.                                       & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;  
  117.                             sleeps = (mEndcallBehavior  
  118.                                       & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;  
  119.                         } else {  
  120.                             gohome = false;  
  121.                             sleeps = true;  
  122.                         }  
  123. if (keyguardActive  
  124.                                 || (sleeps && !gohome)  
  125.                                 || (gohome && !goHome() && sleeps)) {  
  126. // they must already be on the keyguad or home screen,
  127. // go to sleep instead
  128.                             Log.d(TAG, "I'm tired mEndcallBehavior=0x"
  129.                                     + Integer.toHexString(mEndcallBehavior));  
  130.                             result &= ~ACTION_POKE_USER_ACTIVITY;  
  131.                             result |= ACTION_GO_TO_SLEEP;  
  132.                         }  
  133.                         result &= ~ACTION_PASS_TO_USER;  
  134.                     }  
  135.                 }  
  136.             } elseif (isMediaKey(code)) {  
  137. // This key needs to be handled even if the screen is off.
  138. // If others need to be handled while it's off, this is a reasonable
  139. // pattern to follow.
  140. if ((result & ACTION_PASS_TO_USER) == 0) {  
  141. // Only do this if we would otherwise not pass it to the user. In that
  142. // case, the PhoneWindow class will do the same thing, except it will
  143. // only do it if the showing app doesn't process the key on its own.
  144.                     KeyEvent keyEvent = new KeyEvent(event.when, event.when,  
  145.                             down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,  
  146.                             code, 0);  
  147.                     mBroadcastWakeLock.acquire();  
  148.                     mHandler.post(new PassHeadsetKey(keyEvent));  
  149.                 }  
  150.             } elseif (code == KeyEvent.KEYCODE_CALL) {  
  151. // If an incoming call is ringing, answer it!
  152. // (We handle this key here, rather than in the InCallScreen, to make
  153. // sure we'll respond to the key even if the InCallScreen hasn't come to
  154. // the foreground yet.)
  155. // We answer the call on the DOWN event, to agree with
  156. // the "fallback" behavior in the InCallScreen.
  157. if (down) {  
  158. try {  
  159.                         ITelephony phoneServ = getPhoneInterface();  
  160. if (phoneServ != null) {  
  161. if (phoneServ.isRinging()) {  
  162.                                 Log.i(TAG, "interceptKeyTq:"
  163.                                       + " CALL key-down while ringing: Answer the call!");  
  164.                                 phoneServ.answerRingingCall();  
  165. // And *don't* pass this key thru to the current activity
  166. // (which is presumably the InCallScreen.)
  167.                                 result &= ~ACTION_PASS_TO_USER;  
  168.                             }  
  169.                         } else {  
  170.                             Log.w(TAG, "CALL button: Unable to find ITelephony interface");  
  171.                         }  
  172.                     } catch (RemoteException ex) {  
  173.                         Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);  
  174.                     }  
  175.                 }  
  176.             } elseif ((code == KeyEvent.KEYCODE_VOLUME_UP)  
  177.                        || (code == KeyEvent.KEYCODE_VOLUME_DOWN)) {  
  178. // If an incoming call is ringing, either VOLUME key means
  179. // "silence ringer".  We handle these keys here, rather than
  180. // in the InCallScreen, to make sure we'll respond to them
  181. // even if the InCallScreen hasn't come to the foreground yet.
  182. // Look for the DOWN event here, to agree with the "fallback"
  183. // behavior in the InCallScreen.
  184. if (down) {  
  185. try {  
  186.                         ITelephony phoneServ = getPhoneInterface();  
  187. if (phoneServ != null) {  
  188. if (phoneServ.isRinging()) {  
  189.                                 Log.i(TAG, "interceptKeyTq:"
  190.                                       + " VOLUME key-down while ringing: Silence ringer!");  
  191. // Silence the ringer.  (It's safe to call this
  192. // even if the ringer has already been silenced.)
  193.                                 phoneServ.silenceRinger();  
  194. // And *don't* pass this key thru to the current activity
  195. // (which is probably the InCallScreen.)
  196.                                 result &= ~ACTION_PASS_TO_USER;  
  197.                             }  
  198.                         } else {  
  199.                             Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");  
  200.                         }  
  201.                     } catch (RemoteException ex) {  
  202.                         Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);  
  203.                     }  
  204.                 }  
  205.             }  
  206.         }  
  207. return result;  
  208.     }  
//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 plaincopyprint?
  1. privatevoid process() {  
  2.            android.os.Process.setThreadPriority(  
  3.                    android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);  
  4. // The last key event we saw
  5.            KeyEvent lastKey = null;  
  6. // Last keydown time for auto-repeating keys
  7. long lastKeyTime = SystemClock.uptimeMillis();  
  8. long nextKeyTime = lastKeyTime+LONG_WAIT;  
  9. long downTime = 0;  
  10. // How many successive repeats we generated
  11. int keyRepeatCount = 0;  
  12. // Need to report that configuration has changed?
  13. boolean configChanged = false;  
  14. while (true) {  
  15. long curTime = SystemClock.uptimeMillis();  
  16. if (DEBUG_INPUT) Slog.v(  
  17.                    TAG, "Waiting for next key: now=" + curTime  
  18.                    + ", repeat @ " + nextKeyTime);  
  19. // Retrieve next event, waiting only as long as the next
  20. // repeat timeout.  If the configuration has changed, then
  21. // don't wait at all -- we'll report the change as soon as
  22. // we have processed all events.
  23.                QueuedEvent ev = mQueue.getEvent(//*****獲取佇列中的訊息***//
  24.                    (int)((!configChanged && curTime < nextKeyTime)  
  25.                            ? (nextKeyTime-curTime) : 0));  
  26. if (DEBUG_INPUT && ev != null) Slog.v(  
  27.                        TAG, "Event: type=" + ev.classType + " data=" + ev.event);  
  28. if (MEASURE_LATENCY) {  
  29.                    lt.sample("2 got event              ", System.nanoTime() - ev.whenNano);  
  30.                }  
  31. if (lastKey != null && !mPolicy.allowKeyRepeat()) {  
  32. // cancel key repeat at the request of the policy.
  33.                    lastKey = null;  
  34.                    downTime = 0;  
  35.                    lastKeyTime = curTime;  
  36.                    nextKeyTime = curTime + LONG_WAIT;  
  37.                }  
  38. try {  
  39. if (ev != null) {  
  40.                        curTime = SystemClock.uptimeMillis();  
  41. int eventType;  
  42. if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {  
  43.                            eventType = eventType((MotionEvent)ev.event);  
  44.                        } elseif (ev.classType == RawInputEvent.CLASS_KEYBOARD ||  
  45.                                    ev.classType == RawInputEvent.CLASS_TRACKBALL) {  
  46.                            eventType = LocalPowerManager.BUTTON_EVENT;  
  47.                        } else {  
  48.                            eventType = LocalPowerManager.OTHER_EVENT;  
  49.                        }  
  50. try {  
  51. if ((curTime - mLastBatteryStatsCallTime)  
  52.                                    >= MIN_TIME_BETWEEN_USERACTIVITIES) {  
  53.                                mLastBatteryStatsCallTime = curTime;  
  54.                                mBatteryStats.noteInputEvent();  
  55.                            }  
  56.                        } catch (RemoteException e) {  
  57. // Ignore
  58.                        }  
  59. if (ev.classType == RawInputEvent.CLASS_CONFIGURATION_CHANGED) {  
  60. // do not wake screen in this case
  61.                        } elseif (eventType != TOUCH_EVENT  
  62.                                && eventType != LONG_TOUCH_EVENT  
  63.                                && eventType != CHEEK_EVENT) {  
  64.                            mPowerManager.userActivity(curTime, false,  
  65.                                    eventType, false);  
  66.                        } elseif (mLastTouchEventType != eventType  
  67.                                || (curTime - mLastUserActivityCallTime)  
  68.                                >= MIN_TIME_BETWEEN_USERACTIVITIES) {  
  69.                            mLastUserActivityCallTime = curTime;  
  70.                            mLastTouchEventType = eventType;  
  71.                            mPowerManager.userActivity(curTime, false,  
  72.