您的位置:首页 > 移动开发 > Android开发

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

2011-10-24 00:59 148 查看
Step 8. NativeInputManager.setInputWindows 这个函数定义在frameworks/base/services/jni/com_android_server_InputManager.cpp 文件中:
  1. void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowObjArray) {  
  2.     Vector<InputWindow> windows;  
  3.   
  4.     jsize length = env->GetArrayLength(windowObjArray);  
  5.     for (jsize i = 0; i < length; i++) {  
  6.         jobject inputTargetObj = env->GetObjectArrayElement(windowObjArray, i);  
  7.         if (! inputTargetObj) {  
  8.             break; // found null element indicating end of used portion of the array  
  9.         }  
  10.   
  11.         windows.push();  
  12.         InputWindow& window = windows.editTop();  
  13.         bool valid = populateWindow(env, inputTargetObj, window);  
  14.         if (! valid) {  
  15.             windows.pop();  
  16.         }  
  17.   
  18.         env->DeleteLocalRef(inputTargetObj);  
  19.     }  
  20.   
  21.     mInputManager->getDispatcher()->setInputWindows(windows);  
  22. }  
        这个函数首先将Java层的Window转换成C++层的InputWindow,然后放在windows向量中,最后将这些输入窗口设置到InputDispatcher中去。           Step 9. InputDispatcher.setInputWindows         这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
  1. void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) {  
  2.     ......  
  3.   
  4.     { // acquire lock  
  5.         AutoMutex _l(mLock);  
  6.   
  7.         // Clear old window pointers.  
  8.         sp<InputChannel> oldFocusedWindowChannel;  
  9.         if (mFocusedWindow) {  
  10.             oldFocusedWindowChannel = mFocusedWindow->inputChannel;  
  11.             mFocusedWindow = NULL;  
  12.         }  
  13.   
  14.         mWindows.clear();  
  15.   
  16.         // Loop over new windows and rebuild the necessary window pointers for  
  17.         // tracking focus and touch.  
  18.         mWindows.appendVector(inputWindows);  
  19.   
  20.         size_t numWindows = mWindows.size();  
  21.         for (size_t i = 0; i < numWindows; i++) {  
  22.             const InputWindow* window = & mWindows.itemAt(i);  
  23.             if (window->hasFocus) {  
  24.                 mFocusedWindow = window;  
  25.                 break;  
  26.             }  
  27.         }  
  28.   
  29.         ......  
  30.   
  31.     } // release lock  
  32.   
  33.     ......  
  34. }  
        这里InputDispatcher的成员变量mFocusedWindow就代表当前激活的窗口的。这个函数首先清空mFocusedWindow,然后再通过一个for循环检查当前的输入窗口中的哪一个窗口是获得焦点的,获得焦点的输入窗口即为当前激活的窗口。           这样,InputManager就把当前激活的Activity窗口保存在InputDispatcher中了,后面就可以把键盘消息分发给它来处理。         回到Step 1中的ViewRoot.setView函数中,接下来就调用下面语句来注册键盘消息接收通道的一端到InputManager中去:
  1. mInputChannel = new InputChannel();  
  2. try {  
  3.     res = sWindowSession.add(mWindow, mWindowAttributes,  
  4.             getHostVisibility(), mAttachInfo.mContentInsets,  
  5.             mInputChannel);  
  6. } catch (RemoteException e) {  
  7.     ......  
  8. } finally {  
  9.     ......  
  10. }  
        前面说过,这里的sWindowSession是WindowManagerService内部类Session的一个远程接口,通过它可以进入到WindowManagerService中去。           Step 10. WindowManagerService.Session.add         这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java 文件中:
  1. public class WindowManagerService extends IWindowManager.Stub  
  2.         implements Watchdog.Monitor {  
  3.     ......  
  4.   
  5.     private final class Session extends IWindowSession.Stub  
  6.             implements IBinder.DeathRecipient {  
  7.         ......  
  8.   
  9.         public int add(IWindow window, WindowManager.LayoutParams attrs,  
  10.                 int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) {  
  11.             return addWindow(this, window, attrs, viewVisibility, outContentInsets,  
  12.                 outInputChannel);  
  13.         }  
  14.   
  15.         ......  
  16.     }  
  17.   
  18.     ......  
  19. }  
        这里调用WindowManagerService类的addWindow函数来进一步执行操作。         Step 11. WindowManagerService.addWindow         这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java 文件中:
  1. public class WindowManagerService extends IWindowManager.Stub  
  2.         implements Watchdog.Monitor {  
  3.     ......  
  4.   
  5.     public int addWindow(Session session, IWindow client,  
  6.             WindowManager.LayoutParams attrs, int viewVisibility,  
  7.             Rect outContentInsets, InputChannel outInputChannel) {  
  8.         ......  
  9.   
  10.         WindowState win = null;  
  11.   
  12.         synchronized(mWindowMap) {  
  13.             ......  
  14.   
  15.             win = new WindowState(session, client, token,  
  16.                 attachedWindow, attrs, viewVisibility);  
  17.   
  18.             ......  
  19.   
  20.             if (outInputChannel != null) {  
  21.                 String name = win.makeInputChannelName();  
  22.                 InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);  
  23.                 win.mInputChannel = inputChannels[0];  
  24.                 inputChannels[1].transferToBinderOutParameter(outInputChannel);  
  25.                 mInputManager.registerInputChannel(win.mInputChannel);  
  26.             }  
  27.   
  28.             ......  
  29.         }  
  30.   
  31.         ......  
  32.     }  
  33.   
  34.     ......  
  35. }  

 

        这里的outInputChannel即为前面在Step 1中创建的InputChannel,它不为NULL,因此,这里会通过InputChannel.openInputChannelPair函数来创建一对输入通道,其中一个位于WindowManagerService中,另外一个通过outInputChannel参数返回到应用程序中: 

  1. inputChannels[1].transferToBinderOutParameter(outInputChannel);  

        创建输入通道之前,WindowManagerService会为当前Activity窗口创建一个WindowState对象win,用来记录这个Activity窗口的状态信息。当创建这对输入管道成功以后,也会把其中的一个管道保存在这个WindowState对象win的成员变量mInputChannel中,后面要注销这个管道的时候,就是从这个WindownState对象中取回这个管道的:

  1. win.mInputChannel = inputChannels[0];  

 

        接下来我们就看一下InputChannel.openInputChannelPair函数的实现。

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: