Android应用程序键盘(Keyboard)消息处理机制分析(22)

      Step 36. ViewRoot.finishInputEvent

         这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:

  1. public final class ViewRoot extends Handler implements ViewParent,  
  2.         View.AttachInfo.Callbacks {  
  3.     ......  
  4.   
  5.     private void finishInputEvent() {  
  6.         ......  
  7.   
  8.         if (mFinishedCallback != null) {  
  9.             mFinishedCallback.run();  
  10.             mFinishedCallback = null;  
  11.         } else {  
  12.             ......  
  13.         }  
  14.     }  
  15.   
  16.     ......  
  17. }  

         ViewRoot类里面的成员变量mFinishedCallback是在前面Step 25中由InputQueue设置的,它是一个Runnable对象,实际类型是定义在InputQueue的内部类FinishedCallback,因此,这里调用它的run方法时,接下来就会调用InputQueue的内部类FinishedCallback的run成员函数:

  1. public final class InputQueue {  
  2.     ......  
  3.   
  4.     private static class FinishedCallback implements Runnable {  
  5.         ......  
  6.   
  7.         public void run() {  
  8.             synchronized (sLock) {  
  9.                 ......  
  10.   
  11.                 nativeFinished(mFinishedToken);  
  12.                   
  13.                 ......  
  14.             }  
  15.         }  
  16.   
  17.         ......  
  18.     }  
  19.   
  20.     ......  
  21. }  

        这里它调用外部类InputQueue的本地方法nativeFinished来进一步处理。

       Step 37.  InputQueue.nativeFinished

        这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:

  1. static void android_view_InputQueue_nativeFinished(JNIEnv* env, jclass clazz,  
  2.         jlong finishedToken) {  
  3.     status_t status = gNativeInputQueue.finished(  
  4.         env, finishedToken, false /*ignoreSpuriousFinish*/);  
  5.   
  6.     ......  
  7. }  
        这个函数只是简单只调用NativeInputQueue的finished方法来进一处处理。

 

        Step 38. NativeInputQueue.finished

        这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:

  1. status_t NativeInputQueue::finished(JNIEnv* env, jlong finishedToken, bool ignoreSpuriousFinish) {  
  2.     int32_t receiveFd;  
  3.     uint16_t connectionId;  
  4.     uint16_t messageSeqNum;  
  5.     parseFinishedToken(finishedToken, &receiveFd, &connectionId, &messageSeqNum);  
  6.   
  7.     { // acquire lock  
  8.         AutoMutex _l(mLock);  
  9.   
  10.         ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd);  
  11.         ......  
  12.   
  13.         sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);  
  14.         ......  
  15.   
  16.         connection->messageInProgress = false;  
  17.   
  18.         status_t status = connection->inputConsumer.sendFinishedSignal();  
  19.           
  20.         ......  
  21.     } // release lock  
  22.   
  23.     return OK;  
  24. }  
        这个函数最重要的参数便是finishedToken了,通过它可以获得之前通知Java层的InputQueue类来处理键盘事件的Connection对象,它的值是在上面的Step 21(NativeInputQueue.handleReceiveCallback)中生成的:

  1. finishedToken = generateFinishedToken(receiveFd, connection->id, connection->messageSeqNum);  

        函数generateFinishedToken的定义如下:

  1. jlong NativeInputQueue::generateFinishedToken(int32_t receiveFd, uint16_t connectionId,  
  2.         uint16_t messageSeqNum) {  
  3.     return (jlong(receiveFd) << 32) | (jlong(connectionId) << 16) | jlong(messageSeqNum);  
  4. }  

        它的实现很简单,只是把receiveFd(前向管道的读端文件描述符)、connectionId(Client端的InputChannel对应的Connection对象在NativeInputQueue中的索引)和messageSeqNum(键盘消息的序列号)三个数值通过移位的方式编码在一个jlong值里面,即编码在上面的finishedToken参数里面。

 

        因此,在上面的finished函数里面,首先就是要对参数值finishedToken进行解码,把receiveFd、connectionId和messageSeqNum三个值分别取回来:

  1. parseFinishedToken(finishedToken, &receiveFd, &connectionId, &messageSeqNum);  

       parseFinishedToken的定义如下:

  1. void NativeInputQueue::parseFinishedToken(jlong finishedToken,  
  2.         int32_t* outReceiveFd, uint16_t* outConnectionId, uint16_t* outMessageIndex) {  
  3.     *outReceiveFd = int32_t(finishedToken >> 32);  
  4.     *outConnectionId = uint16_t(finishedToken >> 16);  
  5.     *outMessageIndex = uint16_t(finishedToken);  
  6. }  

       有了这个receiveFd和connectionId之后,就可以把相应的Connection对象取回来了:

  1. ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd);  
  2.         ......  
  3.   
  4. sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);  

       接下来就是调用这个connection对象中的inputConsumer对象来发送信号通知Server端的InputChannel,应用程序这一侧处理完刚才发生的键盘事件了:

  1. status_t status = connection->inputConsumer.sendFinishedSignal();  

 

 

你可能感兴趣的:(android,keyboard,消息处理机制分析)