android 输入法WINDOW_FOCUS_CHANGED|MSG_CREATE_SESSION|MSG_BIND_INPUT|MSG_START_INPUT|MSG_BIND_METHOD消息

来源:互联网 发布:淘宝店铺红包怎么用啊 编辑:程序博客网 时间:2024/06/03 07:06



当我们从home界面进入到设置界面应用,这个时候设置应用下没有任何输入框,但是这个时候foucs进行了change,而输入法也将进行一次尝试性判断是否需要显示输入法

ViewRootImpl.java 的 case WINDOW_FOCUS_CHANGED: {处理

    InputMethodManager imm = InputMethodManager.peekInstance();                Log.v("PateoInputMethod","ViewRootImpl class " + " ,WINDOW_FOCUS_CHANGED msg,");                if (mView != null) {                    if (hasWindowFocus && imm != null && mLastWasImTarget) {                     Log.v("PateoInputMethod","ViewRootImpl class " + " ,WINDOW_FOCUS_CHANGED msg, imm.startGettingWindowFocus mView=" + mView);                        imm.startGettingWindowFocus(mView);                    }                    mAttachInfo.mKeyDispatchState.reset();                    mView.dispatchWindowFocusChanged(hasWindowFocus);                }                // Note: must be done after the focus change callbacks,                // so all of the view state is set up correctly.                if (hasWindowFocus) {                    if (imm != null && mLastWasImTarget) {                     Log.v("PateoInputMethod","ViewRootImpl class " + " ,WINDOW_FOCUS_CHANGED msg,imm.onWindowFocus");                        imm.onWindowFocus(mView, mView.findFocus(),                                mWindowAttributes.softInputMode,                                !mHasHadWindowFocus, mWindowAttributes.flags);                    }

输出日志:

01-01 09:41:43.840 V/PateoInputMethod( 1757): ViewRootImpl class  ,WINDOW_FOCUS_CHANGED msg,01-01 09:41:43.840 V/PateoInputMethod( 1757): ViewRootImpl class  ,WINDOW_FOCUS_CHANGED msg, imm.startGettingWindowFocus mView=com.android.internal.policy.impl.PhoneWindow$DecorView@418f551801-01 09:41:43.860 V/PateoInputMethod( 1757): ViewRootImpl class  ,WINDOW_FOCUS_CHANGED msg,imm.onWindowFocus

从上面来看,我们进入imm.onWindowFocus的方法进行分析

    /**     * Called by ViewAncestor when its window gets input focus.     * @hide     */    public void onWindowFocus(View rootView, View focusedView, int softInputMode,            boolean first, int windowFlags) {        boolean forceNewFocus = false;        synchronized (mH) {            if (DEBUG) Log.v(TAG,"InputMethodManager class " +  "onWindowFocus: " + focusedView                    + " softInputMode=" + softInputMode                    + " first=" + first + " flags=#"                    + Integer.toHexString(windowFlags));            if (mHasBeenInactive) {                if (DEBUG) Log.v(TAG,"InputMethodManager class " +  "Has been inactive!  Starting fresh");                mHasBeenInactive = false;                forceNewFocus = true;            }            focusInLocked(focusedView != null ? focusedView : rootView);        }        int controlFlags = 0;        if (focusedView != null) {            controlFlags |= CONTROL_WINDOW_VIEW_HAS_FOCUS;            if (focusedView.onCheckIsTextEditor()) {                controlFlags |= CONTROL_WINDOW_IS_TEXT_EDITOR;            }        }        if (first) {            controlFlags |= CONTROL_WINDOW_FIRST;        }                if (checkFocusNoStartInput(forceNewFocus)) {            // We need to restart input on the current focus view.  This            // should be done in conjunction with telling the system service            // about the window gaining focus, to help make the transition            // smooth.        Log.d(TAG, "InputMethodManager class onWindowFocus method");            if (startInputInner(rootView.getWindowToken(),                    controlFlags, softInputMode, windowFlags)) {                return;            }        }                // For some reason we didn't do a startInput + windowFocusGain, so        // we'll just do a window focus gain and call it a day.        synchronized (mH) {            try {                mService.windowGainedFocus(mClient, rootView.getWindowToken(),                        controlFlags, softInputMode, windowFlags, null, null);            } catch (RemoteException e) {            }        }    }

相应的日志输入Log.d(TAG, "InputMethodManager class onWindowFocus method");  发现进入了startInputInner方法,在此方法中,根据相应的输出日志我们发现走入了如下代码行:

                if (windowGainingFocus != null) {                if (DEBUG) Log.v(TAG,"InputMethodManager class " + " IInputMethodManager.windowGainedFocus");                    res = mService.windowGainedFocus(mClient, windowGainingFocus,                            controlFlags, softInputMode, windowFlags,                            tba, servedContext);                } 
进入该InputMethodManagerService的windowGainedFocus方法

switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:                        if (!isTextEditor || !doAutoShow) {                            if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) {                                // There is no focus view, and this window will                                // be behind any soft input window, so hide the                                // soft input window if it is shown.                                if (DEBUG) Slog.v(TAG, "InputMethodManagerService class" +  "Unspecified window will hide input");                                hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);                            }                        } 

输出日志:Unspecified window will hide input,在上面的switch代码行下面还有如下必覆盖代码:

if (!didStart && attribute != null) {                    res = startInputUncheckedLocked(cs, inputContext, attribute,                            controlFlags);                }

进入该startInputUncheckedLocked方法

    InputBindResult startInputUncheckedLocked(ClientState cs,            IInputContext inputContext, EditorInfo attribute, int controlFlags) {        // If no method is currently selected, do nothing.        if (mCurMethodId == null) {            return mNoBinding;        }        if (mCurClient != cs) {            // If the client is changing, we need to switch over to the new            // one.            unbindCurrentClientLocked();            if (DEBUG) Slog.v(TAG, "InputMethodManagerService class" +  "switching to client: client = "                    + cs.client.asBinder());            // If the screen is on, inform the new client it is active            if (mScreenOn) {                try {                    cs.client.setActive(mScreenOn);                } catch (RemoteException e) {                    Slog.w(TAG, "InputMethodManagerService class" +  "Got RemoteException sending setActive notification to pid "                            + cs.pid + " uid " + cs.uid);                }            }        }        // Bump up the sequence for this client and attach it.        mCurSeq++;        if (mCurSeq <= 0) mCurSeq = 1;        mCurClient = cs;        mCurInputContext = inputContext;        mCurAttribute = attribute;        // Check if the input method is changing.        if (mCurId != null && mCurId.equals(mCurMethodId)) {            if (cs.curSession != null) {                // Fast case: if we are already connected to the input method,                // then just return it.            Slog.w(TAG, "InputMethodManagerService class" + "startInputUncheckedLocked method ,attachNewInputLocked");                return attachNewInputLocked(                        (controlFlags&InputMethodManager.CONTROL_START_INITIAL) != 0);            }            if (mHaveConnection) {                if (mCurMethod != null) {                    if (!cs.sessionRequested) {                        cs.sessionRequested = true;                        if (DEBUG) Slog.v(TAG, "InputMethodManagerService class" +  "Creating new session for client " + cs);                        executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(                                MSG_CREATE_SESSION, mCurMethod,                                new MethodCallback(mCurMethod, this)));                    }                    // Return to client, and we will get back with it when                    // we have had a session made for it.                    return new InputBindResult(null, mCurId, mCurSeq);                } else if (SystemClock.uptimeMillis()                        < (mLastBindTime+TIME_TO_RECONNECT)) {                    // In this case we have connected to the service, but                    // don't yet have its interface.  If it hasn't been too                    // long since we did the connection, we'll return to                    // the client and wait to get the service interface so                    // we can report back.  If it has been too long, we want                    // to fall through so we can try a disconnect/reconnect                    // to see if we can get back in touch with the service.                    return new InputBindResult(null, mCurId, mCurSeq);                } else {                    EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,                            mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);                }            }        }        return startInputInnerLocked();    }

我们先看上面方法中的如下一行代码

unbindCurrentClientLocked();

进入该方法

   void unbindCurrentClientLocked() {        if (mCurClient != null) {            if (DEBUG) Slog.v(TAG, "InputMethodManagerService class" +  "unbindCurrentInputLocked: client = "                    + mCurClient.client.asBinder());            if (mBoundToMethod) {                mBoundToMethod = false;                if (mCurMethod != null) {                    executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(                            MSG_UNBIND_INPUT, mCurMethod));                }            }                                       try {           mCurSeq = ((IInputMethodClient)mCurClient.client).getBindSequence();        } catch (RemoteException e) {        }                        executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(                    MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));            mCurClient.sessionRequested = false;            // Call setActive(false) on the old client            try {                mCurClient.client.setActive(false);            } catch (RemoteException e) {                Slog.w(TAG, "InputMethodManagerService class" +  "Got RemoteException sending setActive(false) notification to pid "                        + mCurClient.pid + " uid " + mCurClient.uid);            }            mCurClient = null;            hideInputMethodMenuLocked();        }    }

因为mCurClient == null所以该放入内代码未覆盖执行,但是这里需要注意下,如果mCurClient != null 则会MSG_UNBIND_INPUT、MSG_UNBIND_METHOD即其它

这里我们回到startInputUncheckedLocked方法,紧接着我们走入了如下代码:

if (mHaveConnection) {                if (mCurMethod != null) {                    if (!cs.sessionRequested) {                        cs.sessionRequested = true;                        if (DEBUG) Slog.v(TAG, "InputMethodManagerService class" +  "Creating new session for client " + cs);                        executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(                                MSG_CREATE_SESSION, mCurMethod,                                new MethodCallback(mCurMethod, this)));                    }                    // Return to client, and we will get back with it when                    // we have had a session made for it.                    return new InputBindResult(null, mCurId, mCurSeq);                }

从这里来看我们开始MSG_CREATE_SESSION消息的处理

            case MSG_CREATE_SESSION:            Slog.d(TAG,"InputMethodManagerService class MSG_CREATE_SESSION msg ");                args = (HandlerCaller.SomeArgs)msg.obj;                try {                    ((IInputMethod)args.arg1).createSession(                            (IInputMethodCallback)args.arg2);                } catch (RemoteException e) {                }                return true;

此进入了当前类的回调sessionCreated

    private static class MethodCallback extends IInputMethodCallback.Stub {        private final IInputMethod mMethod;        private final InputMethodManagerService mParentIMMS;        MethodCallback(final IInputMethod method, final InputMethodManagerService imms) {            mMethod = method;            mParentIMMS = imms;        }        @Override        public void finishedEvent(int seq, boolean handled) throws RemoteException {        Slog.i(TAG, "InputMethodManagerService class" + " ,MethodCallback finishedEvent method");        }        @Override        public void sessionCreated(IInputMethodSession session) throws RemoteException {        Slog.i(TAG, "InputMethodManagerService class" + " ,MethodCallback sessionCreated method");            mParentIMMS.onSessionCreated(mMethod, session);        }    }


    void onSessionCreated(IInputMethod method, IInputMethodSession session) {        synchronized (mMethodMap) {            if (mCurMethod != null && method != null                    && mCurMethod.asBinder() == method.asBinder()) {                if (mCurClient != null) {                    mCurClient.curSession = new SessionState(mCurClient,                            method, session);                    mCurClient.sessionRequested = false;                    Slog.w(TAG, "InputMethodManagerService class" + "onSessionCreated method ,attachNewInputLocked");                    InputBindResult res = attachNewInputLocked(true);                    if (res.method != null) {                    Slog.w(TAG, "InputMethodManagerService class" + "onSessionCreated method ,attachNewInputLocked MSG_BIND_METHOD");                        executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(                                MSG_BIND_METHOD, mCurClient.client, res));                    }                }            }        }    }

相应的输出日志:

onSessionCreated method ,attachNewInputLocked

attachNewInputLocked method coming...,mBoundToMethod=false ,initial=true

onSessionCreated method ,attachNewInputLocked MSG_BIND_METHOD

    InputBindResult attachNewInputLocked(boolean initial) {    if (DEBUG) Slog.v(TAG, "InputMethodManagerService class" +  "attachNewInputLocked method coming...,mBoundToMethod=" + mBoundToMethod + " ,initial=" + initial);        if (!mBoundToMethod) {            executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(                    MSG_BIND_INPUT, mCurMethod, mCurClient.binding));            mBoundToMethod = true;        }        final SessionState session = mCurClient.curSession;        if (initial) {            executeOrSendMessage(session.method, mCaller.obtainMessageOOO(                    MSG_START_INPUT, session, mCurInputContext, mCurAttribute));        } else {            executeOrSendMessage(session.method, mCaller.obtainMessageOOO(                    MSG_RESTART_INPUT, session, mCurInputContext, mCurAttribute));        }        if (mShowRequested) {            if (DEBUG) Slog.v(TAG, "InputMethodManagerService class" +  "Attach new input asks to show input");            showCurrentInputLocked(getAppShowFlags(), null);        }        if (DEBUG) Slog.v(TAG, "InputMethodManagerService class" +  "attachNewInputLocked method coming...");        return new InputBindResult(session.session, mCurId, mCurSeq);    }

从上面来看,执行了MSG_BIND_INPUT、MSG_START_INPUT、MSG_BIND_METHOD消息,上面即初始化的过程,而这个过程中虽然MSG_START_INPUT了,但是这个最终调用InputMethodService

        public void startInput(InputConnection ic, EditorInfo attribute) {            if (DEBUG) Log.v(TAG,"InputMethodService class" +  "startInput(): editor=" + attribute);            doStartInput(ic, attribute, false);        }

进入该方法

    void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {        if (!restarting) {            doFinishInput();        }        mInputStarted = true;        mStartedInputConnection = ic;        mInputEditorInfo = attribute;        initialize();        if (DEBUG) Log.v(TAG,"InputMethodService class" +  "CALL: onStartInput , mWindowVisible=" + mWindowVisible);        onStartInput(attribute, restarting);        if (mWindowVisible) {            if (mShowInputRequested) {                if (DEBUG) Log.v(TAG,"InputMethodService class" +  "CALL: onStartInputView");                mInputViewStarted = true;                onStartInputView(mInputEditorInfo, restarting);                startExtractingText(true);            } else if (mCandidatesVisibility == View.VISIBLE) {                if (DEBUG) Log.v(TAG,"InputMethodService class" +  "CALL: onStartCandidatesView");                mCandidatesViewStarted = true;                onStartCandidatesView(mInputEditorInfo, restarting);            }        }    }

看输入日志InputMethodService classCALL: onStartInput , mWindowVisible=false,因为mWindowVisible=false所以未显示输入法界面


上面的初始化过程很重要,很多对象进行了初始化在此过程中,后续MSG_SHOW_SOFT_INPUT的时候会用到上面的变量,输入法的变量而且比较多,需要慢慢梳理









0 0
原创粉丝点击