Android P输入法框架系统--view如何触发绑定

    在PC时代,输入法的原始输入来自实体键盘,鼠标,然后输入法将这些事件对应的ASCII码转换为俄文,中文,当然如果是英文是不需要转换,直接发送即可。而在Android系统里,由于输入法dialog永远没法成为焦点window,所以输入法永远没法获取到按键事件,也就是说输入法的输入数据只能来自触摸事件,输入法显示出键盘(大家称之为软键盘),用户点击键盘UI, 然后输入法将触摸事件所在位置的字符当做原始字符输入,最后组装成更为丰富的字符(多个字符组成拼音,然后转化为中文),然后就是发送到对应的程序。

1、输入法整体框架图

在这里插入图片描述
输入法系统的整个框架如下:
InputMethodManagerService(下文也称IMMS)负责管理系统的所有输入法,包括输入法service(InputMethodService简称IMS)加载及切换。程序获得焦点时,就会通过InputMethodManager向InputMethodManagerService通知自己获得焦点并请求绑定自己到当前输入法上。同时,当程序的某个需要输入法的view比如EditorView获得焦点时就会通过InputMethodManager向InputMethodManagerService请求显示输入法,而这时InputMethodManagerService收到请求后,会将请求的EditText的数据通信接口发送给当前输入法,并请求显输入法。输入法收到请求后,就显示自己的UI dialog,同时保存目标view的数据结构,当用户实现输入后,直接通过view的数据通信接口将字符传递到对应的View。接下来就来分析这些过程。

2、InputMethodManager创建

每个应用APP程序有一个InputMethodManager实例,这个是应用APP程序和InputMethodManagerService通信的接口,该实例在ViewRootImpl初始化的时候创建。

//frameworks/base/core/java/android/view/ViewRootImpl.java
public ViewRootImpl(Context context, Display display) {
   
     
    mContext = context;  
    mWindowSession = WindowManagerGlobal.getWindowSession();  
}  

//frameworks/base/core/java/android/view/WindowManagerGlobal.java
public static IWindowSession getWindowSession() {
   
     
    synchronized (WindowManagerGlobal.class) {
   
     
        if (sWindowSession == null) {
   
     
            try {
   
     
                //这个进程的InputMethodManager实例就生成了  
                InputMethodManager imm = InputMethodManager.getInstance();  
                IWindowManager windowManager = getWindowManagerService();  
            } catch (RemoteException e) {
   
     
                Log.e(TAG, "Failed to open window session", e);  
            }  
        }  
        return sWindowSession;  
    }  
}  
  
public static InputMethodManager getInstance() {
   
     
    synchronized (InputMethodManager.class) {
   
     
        if (sInstance == null) {
   
     
            // InputMethodManager其实就是一个Binder service的proxy  
            IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);  
            IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);  
            sInstance = new InputMethodManager(service, Looper.getMainLooper());  
        }  
        return sInstance;  
    }  
}  

3、APP程序的Window获得焦点

程序的window获得焦点的时序图如下
在这里插入图片描述
哪个程序获得焦点是由系统决定的,是由WindowManagerService决定的,当系统的window状态发生变化时(比如window新增,删除)就会调用函数updateFocusedWindowLocked来更新焦点window。

//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
   
     
    //计算焦点window  ----见3.1
    WindowState newFocus = computeFocusedWindowLocked();  
    if (mCurrentFocus != newFocus) {
   
     
        //焦点window发生变化,post一个message来通知程序焦点发生变化了  
        mH.removeMessages(H.REPORT_FOCUS_CHANGE);  
        mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE); //见3.2
        //省略.....
        return true;  
    }  
    return false;  
}  

3.1 焦点window计算

//frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java  
WindowState computeFocusedWindow() {
   
   
    // While the keyguard is showing, we must focus anything besides the main display.
    // Otherwise we risk input not going to the keyguard when the user expects it to.
    final boolean forceDefaultDisplay = mService.isKeyguardShowingAndNotOccluded();

    for (int i = mChildren.size() - 1; i >= 0; i--) {
   
   
        final DisplayContent dc = mChildren.get(i);
        final WindowState win = dc.findFocusedWindow();
        if (win != null) {
   
   
            if (forceDefaultDisplay && !dc.isDefaultDisplay) {
   
   
                EventLog.writeEvent(0x534e4554, "71786287", win.mOwnerUid, "");
                continue;
            }
            return win;
        }
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值