Android应用程序键盘(Keyboard)消息处理机制分析(27)
Step 14.NativeInputQueue.unregisterInputChannel
这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:
- status_tNativeInputQueue::unregisterInputChannel(JNIEnv*env,jobjectinputChannelObj){
- sp<InputChannel>inputChannel=android_view_InputChannel_getInputChannel(env,
- inputChannelObj);
- ......
- {//acquirelock
- AutoMutex_l(mLock);
- ssize_tconnectionIndex=getConnectionIndex(inputChannel);
- ......
- sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
- mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
- connection->status=Connection::STATUS_ZOMBIE;
- connection->looper->removeFd(inputChannel->getReceivePipeFd());
- env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
- connection->inputHandlerObjGlobal=NULL;
- ......
- }//releaselock
- ......
- returnOK;
- }
真正的注销工作就是这里实现的了,读者可以对照前面介绍应用程序注册键盘消息接收通道过程中的Step 21(NativeInputQueue.registerInputChannel)来分析,它首先是将在之前创建的Connection对象从NativeInputQueue中的mConnectionByReceiveFd向量中删除:
- ssize_tconnectionIndex=getConnectionIndex(inputChannel);
- ......
- sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
- mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
然后再把这个Client端InputChannel的前向管道的读端文件描述符从应用程序主线程中的Looper对象中删除:
- connection->looper->removeFd(inputChannel->getReceivePipeFd());
这样,这个Activity窗口以后就不会接收到键盘事件了。
最后将Connection对象中的回调对象inputHandlerOjbGlobal对象删除:
- env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
- connection->inputHandlerObjGlobal=NULL;
回忆一下前面我们在分析InputManager分发键盘消息给应用程序处理时,曾经说到,每当有键盘事件发生时,InputManager首先就会调用NativeInputQueue类的handleReceiveCallback函数。在这个handleReceiveCallback函数里面,NativeInputQueue会找到相应的Connection对象,然后把它里面的内部对象inputHandlerOjbGlobal作为参数来调用Java层的InputQueue类的dispatchKeyEvent函数来通知应用程序,有键盘事件发生了。在InputQueue类的dispatchKeyEvent函数里面,就是通过这个inputHandlerOjbGlobal对象来直正通知到当前激活的Activity窗口来处理这个键盘事件的。
注册在应用程序这一侧的Client端InputChannel被注销以后,回到前面的Step 11中,我们继续分析注销注册在InputManager这一侧的Server端InputChannel。Step 15. WindowManagerService.Session.remove
这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:
- publicclassWindowManagerServiceextendsIWindowManager.Stub
- implementsWatchdog.Monitor{
- ......
- privatefinalclassSessionextendsIWindowSession.Stub
- implementsIBinder.DeathRecipient{
- ......
- publicvoidremove(IWindowwindow){
- removeWindow(this,window);
- }
- ......
- }
- ......
- }
这个函数只是简单地调用其外部类WindowManagerService的removeWindow函数来进一步执行操作。
Step 16.WindowManagerService.removeWindow
这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:
- publicclassWindowManagerServiceextendsIWindowManager.Stub
- implementsWatchdog.Monitor{
- ......
- publicvoidremoveWindow(Sessionsession,IWindowclient){
- synchronized(mWindowMap){
- WindowStatewin=windowForClientLocked(session,client,false);
- if(win==null){
- return;
- }
- removeWindowLocked(session,win);
- }
- }
- ......
- }
回忆一下前面我们在分析应用程序注册键盘消息管道的过程时,在Step 11(WindowManagerService.addWindow)中,WindowManagerService为这个即将要激活的Activity窗口创建了一个WindowState对象win,创建的时候,使用了从ViewRoot中传过来的两个参数,分别是一个Session对象session和一个IWindow对象client。
在这个函数中,ViewRoot传过来的两个参数session和client和上面说的两个参数是一致的,因此,这个函数首先通过参数session和client得到一个WindowState对象win,然后调用removeWindowLocked来把它从WindowManagerService删除。
Step 17.WindowManagerService.removeWindowLocked
这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:
- publicclassWindowManagerServiceextendsIWindowManager.Stub
- implementsWatchdog.Monitor{
- ......
- publicvoidremoveWindowLocked(Sessionsession,WindowStatewin){
- ......
- win.disposeInputChannel();
- ......
- }
- ......
- }
我们忽略了这个函数的其它逻辑,只关注注销之前注册的Server端InputChannel的逻辑,这里,注销的操作就是调用win的disposeInputChannel进行的了。
Step 18. WindowState.disposeInputChannel
这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:
- publicclassWindowManagerServiceextendsIWindowManager.Stub
- implementsWatchdog.Monitor{
- ......
- privatefinalclassWindowStateimplementsWindowManagerPolicy.WindowState{
- ......
- voiddisposeInputChannel(){
- if(mInputChannel!=null){
- mInputManager.unregisterInputChannel(mInputChannel);
- mInputChannel.dispose();
- mInputChannel=null;
- }
- }
- ......
- }
- ......
- }
更多相关文章
- Android应用程序键盘(Keyboard)消息处理机制分析(17)
- Android Apk反编译函数对应法则
- android 根据文件的扩展名选择用什么应用程序打开
- android将对象写入文件和从文件中读取对象数据
- Android应用程序 启动画面
- Android Activity管理类,用于Activity管理和应用程序退出
- Android 的一些实用的函数
- android中得到所有安装的应用程序及区分其是否为系统应用程序还
- 调用其他应用程序的Activity(打电话,浏览网页,发Email)