android4.1.2inputmethodframework结构分析

来源:互联网 发布:适合男生用的面膜知乎 编辑:程序博客网 时间:2024/05/21 15:23
以下来自android官网的介绍:
input method framework (IMF) architecture包含三个主要部分:
1.input method manager是负责管理其他部分交互的中心点;以client-side API的形式存在于每个应用上下文中,
并与一个负责管理跨进程交互的全局系统服务(InputMethodManagerService)通信。
2.input method (IME) 实现一个具体的交互模型,这个模型允许用户产生text文本.系统绑定到当前的
input method,使当前的input method创建运行,并负责通知它什么时候隐藏和显示它的UI. 同一时间只有一个
IME在运行。
3.使用IME的多个客户端程序,客户端程序在获得输入焦点,控制IME的状态方面,由input method manager
统一协调.同一时间只有一个客户端程序处于活动状态(与IME协同工作)。
InputMethodManager
input method framework(IMF) architecture 提供的核心系统接口。负责协调应用和当前输入法的交互。
可通过Context.getSystemService()获得此接口的实例。
InputMethodManager是负责管理其他部分交互的中心点,所以InputMethodManager中有分别代表
全局系统服务(InputMethodManagerService),inputmethod和inputmethod客户端的成员变量,分别是:
IInputMethodManager mService     代表InputMethodManagerService;
IInputMethodSession mCurMethod   代表inputmethod;
IInputMethodClient.Stub mClient  代表inputmethod客户端;

IInputMethodManager接口的具体实现类是InputMethodManagerService。这个类提供系统服务,运行在
一个单独的进程中。InputMethodManager中包含的IInputMethodManager实例mService指向的是
InputMethodManagerService的本地binder对象。
InputMethodManager通过mService与InputMethodManagerService通信。

IInputMethodClient接口的具体实现类是IInputMethodClient.Stub.
InputMethodManager.mClient是这个接口的实例,用于在InputMethodManager类中标识inputmetod客户端。
inputmethod客户端通过InputMethodManager实例与InputMethodManagerService通信。
InputMethodManager与IInputMethodClient是一对一的关系。
InputMethodManagerService存放了所有的
IInputMethodClient本地binder对象,用于标识所有的inputmethod客户端。
所以InputMethodManagerService与IInputMethodClient是一对多的关系。

下面是IInputMethodClient的本地binder对象添加到InputMethodManagerService中的流程:

viewRootImpl.getWindowSession(){        InputMethodManager imm = InputMethodManager.getInstance(mainLooper);        IWindowManager windowManager = Display.getWindowManager();        sWindowSession = windowManager.openSession(imm.getClient(), imm.getInputContext());         }InputMethodManager.getInstance(){ IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);            IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);            mInstance = new InputMethodManager(service, mainLooper);              }//new InputMethodManager过程会创建InputMethodManager.mClient.调用InputMethodManager的构造函数时,将//InputMethodManagerService的本地binder对象传给了InputMethodManager。WindowManagerService.openSession(){    Session session = new Session(this, client, inputContext);                           }Session.Session(){ mService.mInputMethodManager.addClient(client, inputContext,mUid, mPid);}InputMethodManagerService.addClient(){ mClients.put(client.asBinder(), new ClientState(client, inputContext, uid, pid));}
IInputMethodClient的本地binder对象添加到了InputMethodManagerService的
HashMap<IBinder, ClientState> mClients成员变量中。
InputMethodManagerService通过内置类:
class ClientState {
        final IInputMethodClient client;
        final IInputContext inputContext;
        final int uid;
        final int pid;
        final InputBinding binding;
        boolean sessionRequested;
        SessionState curSession;
}
来保存inputmethod客户端的状态。
final HashMap<IBinder, ClientState> mClients保存了当前所有的inputmethod客户端的。
InputMethodManager对InputMethodManagerService接口的调用都需要传入mClient作为inputmethod客户端的标识。

IInputMethodSession接口的具体实现类是IInputMethodSessionWrapper.
IInputMethodSessionWrapper是InputMethodSession接口的具体实现类的封装类。InputMethodSession接口是

InputMethod接口的一部分。InputMethod接口实际上分为两部分,InputMethod接口提供的是输入法的top-level接

口,提供了访问输入法的所有接口,由于输入法应用中的BIND_INPUT_METHOD权限限制,只有系统可以访问

所有的这些接口。此外,InputMethod接口的createSession()方法可以初始化一个输入法的二级接口
InputMethodSession。这个接口是提供给inputmethod客户端使用的,inputmethod客户端通过这个接口来与
inputmethod通信。由于inputmethod客户端与inputmethod的通信是通过InputMethodManager代理的,
所以InputMethodManager中包含IInputMethodSession的实例。这个实例指向IInputMethodSessionWrapper的
本地binder对象。IInputMethodSessionWrapper运行在输入法进程中。

IInputMethod接口的具体实现类是IInputMethodWrapper。IInputMethodWrapper是InputMethod接口的具体

实现类的封装类。InputMethodManagerService是系统服务进程具有调用输入法所有接口的权限,

所以InputMethodManagerService中包含了IInputMethod接口实例mCurMethod.
这个实例指向IInputMethodWrapper的本地binder对象。
IInputMethodWrapper运行在输入法进程中。

IInputMethodCallback是IInputMethod的辅助接口,inputmethod调用这个接口把结果通知给它的客户端。
IInputMethodCallback的具体实现类是InputMethodManagerService.MethodCallback.
由于inputmetod需要调用这个接口通知结果。所以InputMethodManagerService负责将这个接口注册给
inputmethod,inputmethod进程需要保存InputMethodManagerService.MethodCallback的本地binder对象。
具体保存在类IInputMethodSessionWrapper.InputMethodEventCallbackWrapper
和IInputMethodWrapper.InputMethodSessionCallbackWrapper的实例中。

下面类图反应了与IInputMethodCallback接口相关的类关系:



InputMethod接口的实现类是AbstractInputMethodService.AbstractInputMethodImpl。
InputMethodService.InputMethodImpl是AbstractInputMethodService.AbstractInputMethodImpl的子类。
也是InputMethod接口的具体实现类。提供了一个输入法的所有标准行为。
input method (IME)应用实现为一个Service,通常继承自InputMethodService.
InputMethod的核心接口通常是由InputMethodService提供。IME的实现者只需要提供更高级别的API。
下面的类图给出了input method framework的主要结构:



上面类图中类的关系建立过程大致如下:

AbstractInputMethodService.onBind(){ return new IInputMethodWrapper(this, mInputMethod);}InputMethodManagerService.onServiceConnected(){ executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(                            MSG_CREATE_SESSION, mCurMethod,                            new MethodCallback(mCurMethod, this)));                     }//此时AbstractInputMethodService.onBind()中创建的IInputMethodWrapper实例的本地Binder对象//通过参数传递给了InputMethodManagerService。//保存在InputMethodManagerService的IInputMethod类型变量mCurMethod中。InputMethodManagerService.handleMessage(){case MSG_CREATE_SESSION: ((IInputMethod)args.arg1).createSession(                            (IInputMethodCallback)args.arg2);}//handleMessage处理MSG_CREATE_SESSION消息时调用的是IInputMethodWrapper.createSession(),//InputMethodManagerService.MethodCallback实例以参数形式传递进去。前面讲过//InputMethodManagerService.MethodCallback需要注册给inputmethod进程。注册的时机就是这里。IInputMethodWrapper.createSession(){ mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_CREATE_SESSION, callback));}IInputMethodWrapper.executeMessage(){ case DO_CREATE_SESSION:    inputMethod.createSession(new InputMethodSessionCallbackWrapper(                        mCaller.mContext, (IInputMethodCallback)msg.obj));}//IInputMethodWrapper是在AbstractInputMethodService.onBind()中构造的,它的构造函数需要//InputMethod的实例作为参数,保存在IInputMethodWrapper的inputmethod成员变量中。//InputMethodSessionCallbackWrapper定义在IInputMethodWrapper中。//InputMethodSessionCallbackWrapper的构造函数需要IInputMethodCallback作为参数。//InputMethodSessionCallbackWrapper中IInputMethodCallback类型的成员变量mCb保存的是//InputMethodManagerService.MethodCallback的本地binder对象。//AbstractInputMethodService.AbstractInputMethodImpl实现了InputMethod接口,AbstractInputMethodService.AbstractInputMethodImpl.createSession(){callback.sessionCreated(onCreateInputMethodSessionInterface());}InputMethodService.onCreateInputMethodSessionInterface(){return new InputMethodSessionImpl();}//这样就在inputmethod进程中创建了InputMethodSession的实现类(InputMethodService.InputMethodSessionImpl)的一个实例,//并把这个实例作为参数传给了InputMethodSessionCallbackWrapper.sessionCreated()。InputMethodSessionCallbackWrapper.sessionCreated(){  IInputMethodSessionWrapper wrap =                            new IInputMethodSessionWrapper(mContext, session);                    mCb.sessionCreated(wrap);}//InputMethodSessionCallbackWrapper.sessionCreated()以InputMethodSessionImpl实例为参数创建了//IInputMethodSessionWrapper的实例。并将这个实例通过InputMethodSessionCallbackWrapper中IInputMethodCallback//类型的成员变量mCb传递出去。前面讲过InputMethodSessionCallbackWrapper中IInputMethodCallback类型的成员变量mCb保存的是//InputMethodManagerService.MethodCallback的本地binder对象。//所以 mCb.sessionCreated(wrap)最终调用的是InputMethodManagerService.MethodCallback.sessionCreated()。InputMethodManagerService.MethodCallback.sessionCreated(){mParentIMMS.onSessionCreated(mMethod, session);}InputMethodManagerService.onSessionCreated(){  executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(                                MSG_BIND_METHOD, mCurClient.client, res));}InputMethodManagerService.handleMessage(){case MSG_BIND_METHOD: ((IInputMethodClient)args.arg1).onBindMethod(InputMethodSessionCallbackWrapper                            (InputBindResult)args.arg2);}//前面提过这里的IInputMethodClient指向的是InputMethodManager的类型为IInputMethodClient.Stub的成员变量mClient.InputMethodManager.IInputMethodClient.Stub.onBindMethod(){mH.sendMessage(mH.obtainMessage(MSG_BIND, res));}InputMethodManager.H.handleMessage(){ case MSG_BIND:mCurMethod = res.method;startInputInner(null, 0, 0, 0);}//所以InputMethodManager中保存的是IInputMethodSessionWrapper的客户端Binder.
InputConnection接口是InputMethod与接收输入的inputmethod客户端的通信渠道。
InputConnection接口由InputMethod调用,用来读取游标附近的文本,提交文本到text box,传递原始的key event给客户端。
InputConnection接口的具体实现类是BaseInputConnection和InputConnectionWrapper。
以浏览器与inputmethod的交互为例,看一下InputConnection相关的结构。
下面是InputConnection的类图。


下面是上面类图中类关系的建立过程:

InputMethodManager.startInputInner(){InputConnection ic = view.onCreateInputConnection(tba);servedContext = new ControlledInputConnectionWrapper(vh.getLooper(), ic, this);mServedInputConnectionWrapper = servedContext;res = mService.startInput(mClient,                            servedContext, tba, controlFlags);}//WebViewClassic.java有一个内部类WebViewInputConnection。//WebViewInputConnection继承自BaseInputConnection。//所以InputConnection ic = view.onCreateInputConnection(tba);得到的是WebViewInputConnection的实例。//以这个实例为参数创建了InputMethodManager.ControlledInputConnectionWrapper实例。//这个实例传递给了InputMethodManagerService.startInput。InputMethodManagerService.startInput(){                return startInputLocked(client, inputContext, attribute, controlFlags);}startInputUncheckedLocked(){ return attachNewInputLocked(                        (controlFlags&InputMethodManager.CONTROL_START_INITIAL) != 0);}InputMethodManagerService.attachNewInputLocked(){ executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(                    MSG_BIND_INPUT, mCurMethod, mCurClient.binding));}InputMethodManagerService.handleMessage(){case MSG_START_INPUT: session.method.startInput((IInputContext)args.arg2,                            (EditorInfo)args.arg3);}//这里的session.method是IInputMethodWrapper的本地Binder对象。IInputMethodWrapper.startInput(){ mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_START_INPUT,                inputContext, attribute));}IInputMethodWrapper.executeMessage(){case DO_START_INPUT:InputConnection ic = inputContext != null                        ? new InputConnectionWrapper(inputContext) : null;                EditorInfo info = (EditorInfo)args.arg2;                info.makeCompatible(mTargetSdkVersion);                inputMethod.startInput(ic, info);}//以包含WebViewInputConnection实例的InputMethodManager.ControlledInputConnectionWrapper实例为参数创建了//InputConnectionWrapper。所以这里其实有两层封装,InputMethodManager.ControlledInputConnectionWrapper//对WebViewInputConnection的封装,以及InputConnectionWrapper对InputMethodManager.ControlledInputConnectionWrapper//的封装。应用程序开始接收text,并且这个InputMethod实例准备好处理接收到的事件并将产生的text传递给应用程序时,//InputMethod.startInput()被调用。//调用完InputMethod.startInput()后,InputConnectionWrapper的实例就传递给了InputMethodService。//并保存在InputMethodService的InputConnection类型成员变量mInputConnection中。//InputMethodService提供了getCurrentInputConnection()接口获得minputconnection。//InputConnectionWrapper类在包com.android.internal.view中。
另外,
InputMethodManager.ControlledInputConnectionWrapper
InputMethodManager构造过程中创建以下变量:
final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
InputMethodManager构造函数中,
mIInputContext = new ControlledInputConnectionWrapper(looper,
                mDummyInputConnection, this);
这个过程中创建的InputContext会在IInputMethodClient的本地binder对象添加到
InputMethodManagerService的过程中一起注册到InputMethodManagerService中。

下面内容来自android官网对InputMethod接口的介绍:
Input Methods
input method (IME) 实现为一个Service,通常继承自InputMethodService. 它必须提供InputMethod核心接口。
InputMethod的核心接口通常是由InputMethodService提供。IME的实现者只需要提供更高级别的API.
BIND_INPUT_METHOD 权限在输入法实现的AndroidManifest.xml中申请。
input method的客户端只能操作它的InputMethodSession接口. 每个客户端都有一个InputMethodSession接口。
只有与活动客户端相关联的InputMethodSession接口调用才会被当前的IME处理。
对于一般的IME,这条规则由AbstractInputMethodService强制保证。但对于定制raw InputMethodSession实现的IME,
则需要显式处理。只有活动客户端的InputConnection才能接受操作。IMF告诉每个客户端它是否是活动的,
framework强制保证非活动进程在当前InputConnection上的调用都会被忽略。
这保证了当前IME只会把events和text edits发送给当前获得焦点的,用户看到的UI.
inputMethodService 提供了InputMethod的一个标准实现, 最终的inputMethod 实现继承并定制inputMethodService.
InputMethodService为标准UI元素(input view, candidates view, and running in fullscreen mode)

提供了一个基本框架,但是怎么使用它们是由IME的特定实现者决定的。比如,一个IME使用keyboard实现

inputarea,另一个IME允许用户画text,第三个IME可能根本没有对用户可见的输入区域,而是通过监听audio,

然后把speech转换为text.所有的布局元素都放在一个单独的window中,这个window由

InputMethodService管理。这些布局元素包括:

The soft input view, 如果可用,位于屏幕底部。
The candidates view, 如果当前在显示,位于soft input view之上。
soft input view 是大部分输入法的核心,大部分用户交互发生在这里:
按键,画字符,或者其他任何你的ime生成text的操作都发生在这里。
Candidates View 当用户生成text时,ime会想提供一个关于输入的text的可能的翻译列表供用户选择。
这通过candidates view来完成,像soft input view 一样, 实现 onCreateCandidatesView() 来实例化
实现candidats UI的view.
Generating Text
IME的核心部分当然是为应用产生text.
这是通过调用InputConnection接口来完成的。这个接口可以通过getCurrentInputConnection()获得。
This interface allows you to generate raw key events 。
InputMethod接口代表一个可以产生键值和文本的输入法,处理各种输入事件,并将文本返回给请求文本输入的应用程序。


原创粉丝点击