Android输入法框架(Input Method Framework,IMF)是Android中非常重要的模块,它分布于三个部分(确切的说,是三个进程),

  1. 包含编辑框的客户(Client)app,表示普通的使用输入法的app进程。当点击编辑框时,会切换出当前选中的输入法;当用户在输入法输入字符,提交候选词,则会更新到编辑框中。为了完成这些行为,它需要跟下面的两个输入法相关服务进行交互。对于普通app开发者而言,他们一般使用系统提供的EditText,该类和其父类TextView已经很好的封装了跟输入法服务之间的交互;如果是自定义的编辑框,则需要自己处理这种交互。
  2. 输入法(input method,IME)服务(service),是具体的输入法进程,例如自带的拉丁输入法或者谷歌,搜狗等拼音输入法。它们一般提供一个输入窗口,可以根据用户的要求打开或者关闭;可以把用户输入的字符和提交的候选词更新给client等等。这是一个用户级别的Service。为了方便开发者编写新的输入法,IMF提供了抽象基类InputMethodService供输入法开发者扩展。
  3. 输入法管理者(Input method manager,IMM)服务(Service),这是一个Android系统级的服务,用于管理多个输入法以及同其他系统服务(例如window manager service)进行交互。这部分代码是app开发者和IME开发者都不需要关心的。

为了方便描述,后文分别称该三个组件为:client,IME和IMM。

这三个部分需用共同合作才能完成输入法的工作。例如打开一个app,并且一个edit框获取了focus焦点。此时client会通知IMM打开输入法,然后IMM查看当前选中的IME,并调用该IME的start操作。这个简单的开始操作需要三个组件的配合。再比如用户提交了候选词,此时IME需要将候选词告诉client。这里须要IME和client的合作。

因为这三个部分是三个进程,所以它们之间必须通过IPC进行通讯。在Android中,IPC机制是通过binder机制和aidl接口进行通信的。

  1. 对于Client而言,它提供了两个接口IInputMethodClient.aidl和IInputContext.aidl。前者是供IMM调用的,后者是供IME调用的。
  2. IMM提供了接口IInputMethodManager.aidl供其他两个组件调用。
  3. IME提供了两个接口IInputMethod.aidl和IInputMethodSession.aidl,前者供IMM调用,后者供client直接调用。

这些调用关系可以参考下图:

Android输入法框架分析(1)-三大组件

这些接口定义都在java/com/android/internal/view目录下。那这些接口是如何实现的呢?

先看client提供的接口。IInputContext是由同一目录下的IInputConnectionWrapper实现的。正如名字所说,它只是一个wrapper,它把接收到的IPC消息委托给你InputConnection的一个实现。例如对于EditText而言,实现是EditableInputConneciton。
在调用方,IME也不是直接操作IInputContext接口。它会调用实现了InputConnection接口的InputConnectionWrapper(也在前面目录下)。该对象封装了从client传过来的IInputContext实例。
对于IME对client的调用操作,它会经历下面流程(以调用commitText为例,它表示提交候选词):

  1. InputConnectionWrapper.commitText被IME进程中其他代码调用。
  2. 委托给IInputContext stub对象。
  3. 通过IPC跨进程传输
  4. IInputConnectionWrapper接受到该消息并调用其commitText处理。
  5. 如果当前在主UI线程,则直接嗲用InputConnection的实现(例如EditableInputConnection)的commitText方法;否则通过handler进行线程间通信。

在IME看来,接口是InputConnection;在client上,实现的也是InputConnection。IInputContext完全被隐藏起来了。所以Android官方文档说IME通过InputConnection接口来操作client。

再看client提供的另外一个接口IInputMethodClient,IMM是直接调用的。IMM的代码就是InputMethodManagerService。在client端,InputMethodManager类中有一个对IInputMethodClient.stub的实现。

对IMM提供的IInputMethodManager接口而言,它是由InputMethodManagerService来实现的。在client端,InputMethodManager的getInstance(是个singleton)会调用ServiceManager.getService(Context.INPUT_METHOD_SERVICE)获取该接口,然后创建InputMethodManager。所以对于client而言,它跟IMM的交互都是通过InputMethodManager来封装完成的,并不需要关心IInputMethodManager接口。对于IME,如果它想操作IMM,也同样通过InputMethodManager。

下面是IME提供的接口。类似于使用InputConnection封装IInputContext,有两个接口InputMethod和InputMethodSession分别对应着了IInputMethod和IInputSession。
对于InputMethod,IInputMethodWrapper实现了IInputMethod.stub。对于收的的IPC请求,都转发给InputMethod实例。一般而言,这个实例是InputMethodService中定义的InputMethodImpl。该实例是InputMethodService的内部类,所以可以操作InputMethodService。对于其客户IMM,InputMethodManagerService会直接调用IInputMethod的方法发起IPC请求。
对于InputMethodSessoin,非常类似,IInputMethodSessionWrapper实现了IInputMethodSession.stub。同样在InputMethodService中有InputMethodSessionImpl实现了InputMethodSession接口,有一个该类型的对象在IInputMethodSessionWrapper中,负责具体处理过来的IPC消息。在client端,InputMethodManager有一个IInputMethodSession mCurMethod对象。开发者只需要调用InputMethodManager,而由InputMethodManager调用IInputMethodSession的IPC操作。

总结一下,无论是client还是IME的开发者,都不需要直接操作aidl接口。在client端,对于IMM和IME的操作都是通过InputMethodManager发起的,用户甚至不用关心这些IPC操作是发给谁的;在IME端,开发者通过InputConnection给client发IPC消息,通过InputMethodManager给IMM发。而在IMM端,虽然是直接操作aidl接口的stub对象,但因为一般开发者不需要改写它,所以也无关紧要。通过这种方式,简化了开发者的跨进程操作。

最后再总结下代码位置:

  • 所有的aidl接口都在java/com/android/internal/view目录下。它只是internal可见,所以普通开发者无法直接访问它。
  • 用户可以访问的接口或类,包括InputConnection,InputMethodManager,InputMethod,InputMethodSession都在java/android/view/inputmethod目录下。
  • java/com/android/internal/view还包含IInputConnecitonWrapper,InputConnectionWrapper。
  • java/android/view/inputmethod还包含BaseInputConnection
  • java/android/inputmethodservice包含IME端相关代码,例如IInputMethodWrapper,IInputMethodSessionWrapper,InputMethodImpl,InputMethodSessionImpl,InputMethodService。
  • IMM的InputMethodManagerService在services/java/com/android/server下。

代码主要就是这四个目录。

更多相关文章

  1. Android替换/修改系统默认输入法
  2. Android 监听按钮点击事件的三种方式(1:匿名内部类;2:外部类;3:接口方
  3. Android 获取默认输入法,以及获取输入法的列表的方法
  4. Android 沉浸式与输入法冲突
  5. android输入法的四种模式(弹出输入法式的窗口变化)
  6. android edittext只能输入字母和数字,默认弹出英文输入法
  7. android M上可能需要开发者注意的权限大全

随机推荐

  1. No resource identifier found for attri
  2. android高效编程之使用本地变量
  3. ImageButton和Button区别
  4. Android中的TextView超过n行显示省略号
  5. Mac配置Android环境 adb
  6. android TraceView (图形化性能测试工具)
  7. 一个不错的启动菜单显示屏动画效果
  8. 【Android】OpenGL ES for Android(安卓)
  9. Android(安卓)图片预览模仿朋友圈查看图
  10. Android(安卓)studio 真机调试时生成的文