通常显示或者隐藏输入法有以下三个场景
- 当一个窗口焦点改变的时候,会根据Window属性控制输入法的显示
- App主动调用imm::showSoftInput或者imm::hideSoftinputFromWindow
- 输入法自己调用ims:requestShowSelf或者ims:requestHideSelf
Window焦点改变
当window获得焦点时会调用imm::onPostWindowFocus方法
/**
* Called by ViewAncestor when its window gets input focus.
* @hide
*/
public void onPostWindowFocus(View rootView, View focusedView,
@SoftInputModeFlags int softInputMode, boolean first, int windowFlags) {
boolean forceNewFocus = false;
// 对焦点view的控制,后续分析
synchronized (mH) {
if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView
+ " softInputMode=" + InputMethodClient.softInputModeToString(softInputMode)
+ " first=" + first + " flags=#"
+ Integer.toHexString(windowFlags));
if (mRestartOnNextWindowFocus) {
if (DEBUG) Log.v(TAG, "Restarting due to mRestartOnNextWindowFocus");
mRestartOnNextWindowFocus = false;
forceNewFocus = true;
}
focusInLocked(focusedView != null ? focusedView : rootView);
}
.......
// 该方法是对焦点view的判断,这里默认返回true
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.
if (startInputInner(InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN,
rootView.getWindowToken(), controlFlags, softInputMode, windowFlags)) {
return;
}
}
......
}
中间会有一些焦点view的判断,后续分析,这里会进入startInputInner方法
boolean startInputInner(@InputMethodClient.StartInputReason final int startInputReason,
IBinder windowGainingFocus, int controlFlags, int softInputMode,
int windowFlags) {
......
// 在这里创建了焦点View的EditorInfo和InputConnection
EditorInfo tba = new EditorInfo();
tba.packageName = view.getContext().getOpPackageName();
tba.fieldId = view.getId();
InputConnection ic = view.onCreateInputConnection(tba);
if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
synchronized (mH) {
......
// InputConnection被封装成ControlledInputConnectionWrapper,然后被赋值给mServedInputConnectionWrapper对象
ControlledInputConnectionWrapper servedContext;
final int missingMethodFlags;
if (ic != null) {
......
servedContext = new ControlledInputConnectionWrapper(
icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);
} else {
servedContext = null;
missingMethodFlags = 0;
}
mServedInputConnectionWrapper = servedContext;
try {
// 调用imms方法
final InputBindResult res = mService.startInputOrWindowGainedFocus(
startInputReason, mClient, windowGainingFocus, controlFlags, softInputMode,
windowFlags, tba, servedContext, missingMethodFlags,
view.getContext().getApplicationInfo().targetSdkVersion);
......
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId, e);
}
}
return true;
}
在startInputInner中创建当前焦点View的EditorInfo和获取焦点View的InputConnection,在传递给imms前会被封装成ControlledInputConnectionWrapper,然后就从app进程进入了system进程
@NonNull
@Override
public 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,
int unverifiedTargetSdkVersion) {
final InputBindResult result;
if (windowToken != null) {
result = windowGainedFocus(startInputReason, client, windowToken, controlFlags,
softInputMode, windowFlags, attribute, inputContext, missingMethods,
unverifiedTargetSdkVersion);
} else {
result = startInput(startInputReason, client, inputContext, missingMethods, attribute,
controlFlags);
}
if (result == null) {
// This must never happen, but just in case.
Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
+ InputMethodClient.getStartInputReason(startInputReason)
+ " windowFlags=#" + Integer.toHexString(windowFlags)
+ " editorInfo=" + attribute);
return InputBindResult.NULL;
}
return result;
}
@NonNull
private InputBindResult windowGainedFocus(
/* @InputMethodClient.StartInputReason */ final int startInputReason,
IInputMethodClient client, IBinder windowToken, int controlFlags,
/* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
int windowFlags, EditorInfo attribute, IInputContext inputContext,
/* @InputConnectionInspector.missingMethods */ final int missingMethods,
int unverifiedTargetSdkVersion) {
// Needs to check the validity before clearing callin