Step 21.NativeInputQueue.handleReceiveCallback

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

  1. intNativeInputQueue::handleReceiveCallback(intreceiveFd,intevents,void*data){
  2. NativeInputQueue*q=static_cast<NativeInputQueue*>(data);
  3. JNIEnv*env=AndroidRuntime::getJNIEnv();
  4. sp<Connection>connection;
  5. InputEvent*inputEvent;
  6. jobjectinputHandlerObjLocal;
  7. jlongfinishedToken;
  8. {//acquirelock
  9. AutoMutex_l(q->mLock);
  10. ssize_tconnectionIndex=q->mConnectionsByReceiveFd.indexOfKey(receiveFd);
  11. ......
  12. connection=q->mConnectionsByReceiveFd.valueAt(connectionIndex);
  13. ......
  14. status_tstatus=connection->inputConsumer.receiveDispatchSignal();
  15. if(status){
  16. ......
  17. return0;//removethecallback
  18. }
  19. ......
  20. status=connection->inputConsumer.consume(&connection->inputEventFactory,&inputEvent);
  21. ......
  22. finishedToken=generateFinishedToken(receiveFd,connection->id,connection->messageSeqNum);
  23. inputHandlerObjLocal=env->NewLocalRef(connection->inputHandlerObjGlobal);
  24. }//releaselock
  25. ......
  26. int32_tinputEventType=inputEvent->getType();
  27. jobjectinputEventObj;
  28. jmethodIDdispatchMethodId;
  29. switch(inputEventType){
  30. caseAINPUT_EVENT_TYPE_KEY:
  31. ......
  32. inputEventObj=android_view_KeyEvent_fromNative(env,
  33. static_cast<KeyEvent*>(inputEvent));
  34. dispatchMethodId=gInputQueueClassInfo.dispatchKeyEvent;
  35. break;
  36. }
  37. ......
  38. }
  39. ......
  40. env->CallStaticVoidMethod(gInputQueueClassInfo.clazz,
  41. dispatchMethodId,inputHandlerObjLocal,inputEventObj,
  42. jlong(finishedToken));
  43. ......
  44. return1;
  45. }

这个函数首先是通过参数data获得当初注册InputChannel的NativeInputQueue对象,具体可以参考前面介绍的应用程序注册键盘消息接收通道过程的Step 21。接下来再通过参数receiveFd获得保存在这个NativeInputQueue对象中的mConnectionsByReceiveFd成员变量中的Connection对象。有了这个Connection对象后,就可以获得它内部的InputConsumer对象,这个InputConsumer对象是和上面的Step 18中介绍的InputPublisher对象相应的。

在InputChannel内部中,分别有一个InputPublisher对象和一个InputConsumer对象,对于Server端的InputChannel来说,它使用的是InputPublisher对象,通过它进行键盘消息的分发,而对于Client端的InputChannel来说,它使用的是InputConsumer对象,通过它进行键盘消息的读取。

获得了这个InputConsumer对象后首先是调用它的receiveDispatchSignal来确认是否是接收到了键盘消息的通知,如果是的话,再调用它的consume函数来把键盘事件读取出来,最后,调用Java层的回调对象InputQueue的DispatchKeyEvent来处理这个键盘事件。下面,我们就依次来分析这些过程。

Step 22.InputConsumer.receiveDispatchSignal

这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:

  1. status_tInputConsumer::receiveDispatchSignal(){
  2. ......
  3. charsignal;
  4. status_tresult=mChannel->receiveSignal(&signal);
  5. if(result){
  6. returnresult;
  7. }
  8. if(signal!=INPUT_SIGNAL_DISPATCH){
  9. ......
  10. returnUNKNOWN_ERROR;
  11. }
  12. returnOK;
  13. }

这个函数很简单,它通过它内部对象mChannel来从前向管道的读端读入一个字符,看看是否是前面的Step 20中写入的INPUT_SIGNAL_DISPATCH字符。

InputChannel类的receiveSignal函数也是定义在frameworks/base/libs/ui/InputTransport.cpp文件中:

  1. status_tInputChannel::receiveSignal(char*outSignal){
  2. ssize_tnRead;
  3. do{
  4. nRead=::read(mReceivePipeFd,outSignal,1);
  5. }while(nRead==-1&&errno==EINTR);
  6. if(nRead==1){
  7. ......
  8. returnOK;
  9. }
  10. ......
  11. return-errno;
  12. }

Step 23.InputConsumer.consume

这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:

  1. status_tInputConsumer::consume(InputEventFactoryInterface*factory,InputEvent**outEvent){
  2. ......
  3. *outEvent=NULL;
  4. intashmemFd=mChannel->getAshmemFd();
  5. intresult=ashmem_pin_region(ashmemFd,0,0);
  6. ......
  7. if(mSharedMessage->consumed){
  8. ......
  9. returnINVALID_OPERATION;
  10. }
  11. //Acquirebut*neverrelease*thesemaphore.Contentiononthesemaphoreisusedtosignal
  12. //tothepublisherthatthemessagehasbeenconsumed(orisintheprocessofbeing
  13. //consumed).Eventuallythepublisherwillreinitializethesemaphoreforthenextmessage.
  14. result=sem_wait(&mSharedMessage->semaphore);
  15. ......
  16. mSharedMessage->consumed=true;
  17. switch(mSharedMessage->type){
  18. caseAINPUT_EVENT_TYPE_KEY:{
  19. KeyEvent*keyEvent=factory->createKeyEvent();
  20. if(!keyEvent)returnNO_MEMORY;
  21. populateKeyEvent(keyEvent);
  22. *outEvent=keyEvent;
  23. break;
  24. }
  25. ......
  26. }
  27. returnOK;
  28. }

这个函数很简单,只要对照前面的Step 18(InputPublisher.publishKeyEvent)来逻辑来看就可以了,后者是往匿名共享内存中写入键盘事件,前者是从这个匿名共享内存中把这个键盘事件的内容读取出来。

回到Step 21中的handleReceiveCallback函数中,从InputConsumer中获得了键盘事件的内容(保存在本地变量inputEvent中)后,就开始要通知Java层的应用程序了。在前面分析应用程序注册键盘消息接收通道的过程时,在Step 21中(NativeInputQueue.registerInputChannel),会把传进来的对象inputHandlerObj保存在Connection对象中:

  1. connection->inputHandlerObjGlobal=env->NewGlobalRef(inputHandlerObj);

这个inputHandlerObj对象的类型为Java层的InputHandler对象,因此,这里首先把它取回来:

  1. inputHandlerObjLocal=env->NewLocalRef(connection->inputHandlerObjGlobal);

取回来之后,我们要把作为参数来调用InputQueue类的dispatchKeyEvent静态成员函数来通知应用程序,有键盘事件发生了,因此,先找到InputQueue类的静态成员函数dispatchKeyEvent的ID:

  1. dispatchMethodId=gInputQueueClassInfo.dispatchKeyEvent;

在回调用这个InputQueue类的dispatchKeyEvent静态成员函数之前,还要把前面获得的inputEvent对象转换成Java层的KeyEvent对象:

  1. inputEventObj=android_view_KeyEvent_fromNative(env,
  2. static_cast<KeyEvent*>(inputEvent));

万事具备了,就可以通知Java层的InputQueue来处理这个键盘事件了:

  1. env->CallStaticVoidMethod(gInputQueueClassInfo.clazz,
  2. dispatchMethodId,inputHandlerObjLocal,inputEventObj,
  3. jlong(finishedToken));

更多相关文章

  1. Android 软键盘的显示和隐藏
  2. 利用BeautifulSoup的find_all()函数查找某个标签且该标签某属性
  3. 自定义android用户控件,使用回调函数实现自定义事件
  4. 在Android里添加自己的log函数
  5. android 软键盘Enter键事件处理
  6. Android 如何获取当前Activity实例对象?
  7. android中监听软键盘的弹出与隐藏,并获取软键盘的高度
  8. Android触发事件总结(触摸屏事件,手势识别,键盘事件,模拟鼠标/按键事

随机推荐

  1. android Socket 长连接出错:android.syste
  2. Android基础知识总结
  3. android 接听和挂断实现方式
  4. Android(安卓)设置EditText光标Curso颜色
  5. Android事件分发机制全解析
  6. Android的应用程序框架
  7. android的edittext怎么设置不默认被选中
  8. PhoneGap Android(安卓)hello android:mi
  9. PhoneGap android环境设置
  10. Android(安卓)Bundle类别