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
- android 输入法WINDOW_FOCUS_CHANGED|MSG_CREATE_SESSION|MSG_BIND_INPUT|MSG_START_INPUT|MSG_BIND_METHOD消息
- Android输入法框架中按键消息的处理流程
- android 输入法
- Android 输入法
- Android 输入法
- 【Android】【输入法】android 自动弹出输入法
- 消息称百度将发布手机输入法
- Android源码剖析之Framwork层后记篇(硬件消息传递、apk管理、输入法框架、编译过程)
- 修改其他输入法为android 默认输入法
- Android输入法扩展之远程输入法
- Android输入法扩展之远程输入法
- Android输入法扩展之远程输入法
- Android输入法扩展之远程输入法
- Android输入法扩展之远程输入法
- Android打开输入法和关闭输入法
- T9输入法 实现一个Android输入法
- Android上搜狗输入法体验
- android 之输入法
- Python 学习笔记(20140505)
- 在cmd中启动mysql命令行服务
- linux下tomcat 配置
- Android命令行获取WiFi列表以及参数
- 重装win7后恢复ubuntu
- android 输入法WINDOW_FOCUS_CHANGED|MSG_CREATE_SESSION|MSG_BIND_INPUT|MSG_START_INPUT|MSG_BIND_METHOD消息
- 记录一个思路 错误【消息: 'NTES.one(...)' 为空或不是对象 】Chrome没事,ie等内核浏览器报错
- Javascript 严格模式详解 strict 模式
- linux 下安装jdk及配置jdk环境图解
- 表分区 示例
- QTP读取webTable最后一行
- 在Android SQLite中使用事务
- 嵌入Chorm浏览器的开源项目,Delphi版支持D7~XE6
- 使用surfaceview实现camera时,出现拍照后照片花屏问题