這是軟鍵盤的Input Area,主要完成touch screen下和用戶的交互輸入。onCreateInputView() 被調用來進行soft inputview的實例化;onEvaluateInputViewShown() 決定是否顯示soft inputview;當狀態改變的時候,調用updateInputViewShown() 來重新決策是否顯示soft inputview。
onStartInput(EditorInfo, boolean) 處理一個新的輸入。
}
我們知道當一個編輯框獲得焦點的時候,將會create一個新的IME客戶端,那麼IMF框架是怎樣處理這個事件的呢?
首先調用EditText的構造函數EditTex->TextView->setText()
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) imm.restartInput(this);
->startInputInner
void startInputInner() {
final View view;
synchronized (mH) {
view = mServedView;
// Make sure we have a window token for the served view.
if (DEBUG) Log.v(TAG, "Starting input: view=" + view);
if (view == null) {
if (DEBUG) Log.v(TAG, "ABORT input: no served view!");
return;
}
}
// Now we need to get an input connection from the served view.
// This is complicated in a couple ways: we can't be holding our lock
// when calling out to the view, and we need to make sure we call into
// the view on the same thread that is driving its view hierarchy.
Handler vh = view.getHandler();
if (vh == null) {
// If the view doesn't have a handler, something has changed out
// from under us, so just bail.
if (DEBUG) Log.v(TAG, "ABORT input: no handler for view!");
return;
}
if (vh.getLooper() != Looper.myLooper()) {
// The view is running on a different thread than our own, so
// we need to reschedule our work for over there.
if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread");
vh.post(new Runnable() {
public void run() {
startInputInner();
}
});
return;
}
// Okay we are now ready to call into the served view and have it
// do its stuff.
// Life is good: let's hook everything up!
EditorInfo tba = new EditorInfo();
tba.packageName = view.getContext().getPackageName();
tba.fieldId = view.getId();
InputConnection ic = view.onCreateInputConnection(tba); //create 新的InputConnection
if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
synchronized (mH) {
// Now that we are locked again, validate that our state hasn't
// changed.
if (mServedView != view || !mServedConnecting) {
// Something else happened, so abort.
if (DEBUG) Log.v(TAG,
"Starting input: finished by someone else (view="
+ mServedView + " conn=" + mServedConnecting + ")");
return;
}
// If we already have a text box, then this view is already
// connected so we want to restart it.
final boolean initial = mCurrentTextBoxAttribute == null;
// Hook 'em up and let 'er rip.
mCurrentTextBoxAttribute = tba;
mServedConnecting = false;
mServedInputConnection = ic;
IInputContext servedContext;
if (ic != null) {
mCursorSelStart = tba.initialSelStart;
mCursorSelEnd = tba.initialSelEnd;
mCursorCandStart = -1;
mCursorCandEnd = -1;
mCursorRect.setEmpty();
servedContext = new ControlledInputConnectionWrapper(vh.getLooper(), ic);
} else {
servedContext = null;
}
try {
if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
+ ic + " tba=" + tba + " initial=" + initial);
InputBindResult res = mService.startInput(mClient,
servedContext, tba, initial, mCurMethod == null); //啟動IMEservice
if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
if (res != null) {
if (res.id != null) {
mBindSequence = res.sequence;
mCurMethod = res.method;
} else {
// This means there is no input method available.
if (DEBUG) Log.v(TAG, "ABORT input: no input method!");
return;
}
}
if (mCurMethod != null && mCompletions != null) {
try {
mCurMethod.displayCompletions(mCompletions);
} catch (RemoteException e) {
}
}
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId, e);
}
}
那麼到了IME部分的流程又是如何的呢?
首先收到configure change的event調用onConfigurationChanged->inputmethodservice.onConfigurationChanged(conf)
@Override public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
boolean visible = mWindowVisible;
int showFlags = mShowInputFlags;
boolean showingInput = mShowInputRequested;
CompletionInfo[] completions = mCurCompletions;
initViews();
mInputViewStarted = false;
mCandidatesViewStarted = false;
if (mInputStarted) {
doStartInput(getCurrentInputConnection(),
getCurrentInputEditorInfo(), true); //調用startinput,創建IME的input
}
if (visible) {
if (showingInput) {
// If we were last showing the soft keyboard, try to do so again.
if (onShowInputRequested(showFlags, true)) {
showWindow(true);
if (completions != null) {
mCurCompletions = completions;
onDisplayCompletions(completions);
}
} else {
hideWindow();
}
} else if (mCandidatesVisibility == View.VISIBLE) {
// If the candidates are currently visible, make sure the
// window is shown for them.
showWindow(false);
} else {
// Otherwise hide the window.
hideWindow();
}
}
}
doStartInput->initialize->onInitializeInterface->onStartInput->onStartInputView.
onStartInputView中會handle各種IME的event並進一步調用IME自身的onCreate函數,做進一步的初始化以及receiver的rigister。