Android按键消息传播流程

主要涉及的文件有:

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
  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. }  

preporcessEvent调用了InterceptKeyTQ

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

[java]  view plain copy
  1.   /** {@inheritDoc} */  
[java]  view plain copy
  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.     }  
WindowManagerService中的InputDispatcherThread线程process,在里头调用mQueue(KeyQ类)的getEvent函数来获取队列中的消息,处理后分发。

[java]  view plain copy
  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.    }  

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


补充:

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等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值