Android输入法,发现Android输入法框架中按键消息的处理流程和一般应用程序的处理流程有很大的不同,故在此做个总结。
一、一些名词缩写
IMF(InputMethodFramework):输入法框架
IM(InputMethod):输入法
IMS(InputMethodService):输入法服务,一般指一个具体输入法对应的服务
IMMS(InputMethodManagerService):输入法管理器服务,系统进程的一部分,系统中只有一个该服务的实例
IMM(InputMethodManager):输入法管理器,每个客户进程中都包含一个
IME(Input Method Engine/InputMethod Editor):指一个具体的输入法,包括其内部的IMS和Binder对象
CA(Client Application):客户端进程,这里指使用输入法的进程。
二、输入法框架
1、 客户端进程(CA):在每个CA中都存在唯一一个IMM,UI控件(View,TextView,EditText等)可以通过它来访问IMMS,用来操作输入法,比如,打开,关闭,切换输入法等。可以通过Context.getSystemService()和使用InputMethodManager.peekinstance一样的 来获取一个InputMethodManager的实例。
IMM中有2个Binder对象,一个是可编辑UI控件对应的Binder对象(InputContext),输入法进程可以通过InputContext将虚拟按键事件(即通过触屏消息转换而来的按键事件)传递给UI控件;另一个是InputMethodClient,IMMS将通过它访问CA,例如IMMS通过它将IMS的InputMethodSession传递给CA,从而使得CA可以直接访问IMS。
2、输入法进程:和客户端进程类似,它也有2个Binder对象,一个是IMS对应的Binder对象,IMMS将通过它去控制输入法,例如:显示或者隐藏输入法窗口;另一个是专门供客户端使用的Binder对象,客户端主要通过它来向输入法进程传送按键事件。
具体可参见下图:
InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString());
IMMS中
IInputMethod mCurMethod;
IInputMethod是aidl
服务端是 IInputMethodWrapper 子类 在输入法进程中创建
持有final WeakReference
final HandlerCaller mCaller;
final WeakReference
IInputContext mCurInputContext;
IInputMethodClient client;
HashMap
对于客户端使用的InputMethodManager(单例)实例
持有IInputMethodManager接口的代理对象,可以通过aidl与InputMethodManagerService(服务端)交互
还有IInputContext接口实现IInputConnectionWrapper(服务端 主looper,以及InputConnection是BaseInputConnection),而InputConnectionWrapper(客户端),而InputConnectionWrapper封装起来,
还有IInputMethodClient接口,直接接口实例化 回调接口
这样InputMethodManagerService通过IInputMethodClient回调到IInputMethodManager
在EditText等可编辑的UI,获得焦点,触发了View的onFocusChange,
调用InputMethodManager实例化,
同时foucsIn(),
调起startInputInner,
开始通过IInputMethodManager代理对象,访问服务端IMMS的windowGainFocus时参数有IInputMethodClient,IInputContext实例化IInputConnectionWrapper(传入UI控件的looper,以及InputConnection是EditableInputConnection)带入IMMS
IMMS中有ClientState对象,持有IInputContext和IInputMethodClient两个实例
ClientState的实例化,
是通过WindowManageGlobal(单例)的静态方法getWindonSession参数有InputMethodManager的IInputContext和IInputContext
调用WMS的openSession,new Session()参数有WMS,IInputContext,IInputMethodClient
并把IMMS的对象实例化出来通过ServiceManager.getService方式实例化,(此时IMMS相对ServiceManager是客户端)
最终IMMS把IInputContext和IInputMethodClient放入的ClientState。
调用showCurrentInputLocked,bindService 请求客户端的InputMethodService,onBind后,回调onServiceConnection
IMMS中有IInputMethod的客户端对象mCurMethod通过服务绑定,把IInputMethod服务端代理传进来
IInputMethod的服务端是IInputMethodWrapper(参数自定义的InputMethodService和接口
InputMethod的实例),实例化是在绑定服务InputMethodService时onBind实例化
调用IMMS的startInputUncheckedlocked,参数ClientState(mCurClient属性)和IInputContext(mCurInputContext)
调用requestClientSessionLocked参数ClientState,IMMS中的handler(mCaller)创建sesion消息,参数有mCurMethod,InputChannel(native打开两个channel[0]服务端 channel[1]客户端 ),以及IInputSessionCallback接口实现MethodCallback(服务端)(参数有IMMS,mCurMethod,channel[0])
继续调用IInputMethod接口的createSession,参数channel[1]和IInputSessionCallback
找到IInputMethod接口的 服务端IInputMethodWrapper 中属性handler(mCaller)发送创建session的消息 参数channel[1]和IInputSessionCallback。
继续调用IInputMethodWrapper 的属性 mInputMethod (接口InputMethod子类是InputMethodImpl 在类InputMethodService)实例的createSession 参数InputMethod.SessionCallback接口实例InputMethodSessionCallbackWraper(参数channel[1]和IInputSessionCallback),
再次调用InputMethodSessionCallbackWraper的sessionCreate()参数InputMethodSession接口(实例化是InputMethodSessionImpl在类InputMethodService)
开始回调
带着InputMethodSessionImpl实例 InputMethodSessionCallbackWraper的sessionCreated 包裹参数IInputMethodSession的接口IInputMethodSessionWrapper(服务端 参数有channel[1] ,InputMethodSession ,IInputSessionCallback )
主要是打开了ImeinputEventReceiver继承InputEventReceiver(也是
WindowInputEventReceiver的父类) 把channel[1],客户端的通道设置进去
继续回调IInputSessionCallback接口MethodCallback的sessionCreated参数是IInputMethodSession
调用MethodCallback中的IMMS的onSessionCreated参数IInputMethod,channel[0],IInputMethodSession
session创建完毕,开始去绑定输入法
MSG_BIND_METHOD
创建完Session返回调用开始输入法消息
MSG_START_INPUT
InputMethodService子类,onStartInput执行
MSG_SHOW_SOFT_INPUT
显示软键盘和候选字体框