1 Android 输入法框架源码分析总结( 三 )


6 IMMS处理View绑定输入法事件
为了讲解整个绑定过程,我们假设此时输入法还没启动,这个情况下的输入法绑定是最长的,整个过程经历过如下过程:
1) 启动输入法
【1Android 输入法框架源码分析总结】2) 绑定输入法的token
3) 请求输入法为焦点程序创建一个连接会话-
4) 将输入法的接口传递回程序端
5) 绑定输入法和焦点view
1-4是和程序相关的,而5是和view相关的 。所以你可以说1~4是用来绑定程序window和输入法,而5是用来绑定程序view和输入法 。输入法还没启动时,弹出输入法会经过1~5,输入法已经启动,但是焦点window发生变化时会经历3~5,焦点window没有变化,只是改变了焦点view,则只会经历5 。
6.1启动输入法
// InputMethodManagerService.java@Overridepublic InputBindResult startInputOrWindowGainedFocus(/* @InputMethodClient.StartInputReason */ final int startInputReason,IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode,int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,/* @InputConnectionInspector.missingMethods */ final int missingMethods) {if (windowToken != null) {// focusIn 不走该分支return windowGainedFocus(startInputReason, client, windowToken, controlFlags,softInputMode, windowFlags, attribute, inputContext, missingMethods);} else {// view 获得焦点,IMMS将这个 view 和 输入法绑定return startInput(startInputReason, client, inputContext, missingMethods, attribute,controlFlags);}}private InputBindResult startInput(/* @InputMethodClient.StartInputReason */ final int startInputReason,IInputMethodClient client, IInputContext inputContext,/* @InputConnectionInspector.missingMethods */ final int missingMethods,@Nullable EditorInfo attribute, int controlFlags) {if (!calledFromValidUser()) {return null;}synchronized (mMethodMap) {if (DEBUG) {Slog.v(TAG, "startInput: reason="+ InputMethodClient.getStartInputReason(startInputReason)+ " client = " + client.asBinder()+ " inputContext=" + inputContext+ " missingMethods="+ InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)+ " attribute=" + attribute+ " controlFlags=#" + Integer.toHexString(controlFlags));}final long ident = Binder.clearCallingIdentity();try {return startInputLocked(startInputReason, client, inputContext, missingMethods,attribute, controlFlags);} finally {Binder.restoreCallingIdentity(ident);}}}InputBindResult startInputLocked(/* @InputMethodClient.StartInputReason */ final int startInputReason,IInputMethodClient client, IInputContext inputContext,/* @InputConnectionInspector.missingMethods */ final int missingMethods,@Nullable EditorInfo attribute, int controlFlags) {// If no method is currently selected, do nothing.if (mCurMethodId == null) {return mNoBinding;}// 程序在 Service 端 对应的数据结构ClientState cs = mClients.get(client.asBinder());...return startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,controlFlags);}InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,/* @InputConnectionInspector.missingMethods */ final int missingMethods,@NonNull EditorInfo attribute, int controlFlags) {// If no method is currently selected, do nothing.if (mCurMethodId == null) {return mNoBinding;}if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,attribute.packageName)) {Slog.e(TAG, "Rejecting this client as it reported an invalid package name."+ " uid=" + cs.uid + " package=" + attribute.packageName);return mNoBinding;}if (mCurClient != cs) {// 如果新程序和当前活动的程序不同,取消当前活动程序与输入法的绑定// Was the keyguard locked when switching over to the new client?mCurClientInKeyguard = isKeyguardLocked();// If the client is changing, we need to switch over to the new// one.unbindCurrentClientLocked(InputMethodClient.UNBIND_REASON_SWITCH_CLIENT);if (DEBUG) Slog.v(TAG, "switching to client: client="+ cs.client.asBinder() + " keyguard=" + mCurClientInKeyguard);// If the screen is on, inform the new client it is activeif (mIsInteractive) {executeOrSendMessage(cs.client, mCaller.obtainMessageIO(MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, cs));}}// Bump up the sequence for this client and attach it.mCurSeq++;if (mCurSeq