android4.1.2inputmethodframework结构分析

以下来自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接口代表一个可以产生键值和文本的输入法,处理各种输入事件,并将文本返回给请求文本输入的应用程序。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值