标题的意思主要想说明:InputMethodManager 通过 IInputMethodSession访问InputMethodService
先来看按键,back的原始发源地,代码如下:
private void deliverKeyEvent(KeyEvent event, boolean sendDone) {
if (ViewDebug.DEBUG_LATENCY) {
mInputEventDeliverTimeNanos = System.nanoTime();
}
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onKeyEvent(event, 0);
}
// If there is no view, then the event will not be handled.
if (mView == null || !mAdded) {
finishKeyEvent(event, sendDone, false);
return;
}
if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView);
// Perform predispatching before the IME.
if (mView.dispatchKeyEventPreIme(event)) {
finishKeyEvent(event, sendDone, true);
return;
}
// Dispatch to the IME before propagating down the view hierarchy.
// The IME will eventually call back into handleFinishedEvent.
if (mLastWasImTarget) {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
int seq = enqueuePendingEvent(event, sendDone);
if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
+ seq + " event=" + event);
Log.d("PateoInputMethod","ViewRootImpl class deliverKeyEvent method InputMethodManager.dispatchKeyEvent");
imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback);
return;
}
}
从上面看到调用了InputMethodManager的dispatchKeyEvent方法,相应的日志输出如下:
01-01 10:48:36.010 D/PateoInputMethod( 2208): ViewRootImpl class deliverKeyEvent method InputMethodManager.dispatchKeyEvent
进入该方法,代码如下:
public void dispatchKeyEvent(Context context, int seq, KeyEvent key,
IInputMethodCallback callback) {
synchronized (mH) {
if (DEBUG) Log.d(TAG,"InputMethodManager class " + "dispatchKeyEvent");
if (mCurMethod == null) {
try {
callback.finishedEvent(seq, false);
} catch (RemoteException e) {
}
return;
}
if (key.getAction() == KeyEvent.ACTION_DOWN
&& key.getKeyCode() == KeyEvent.KEYCODE_SYM) {
showInputMethodPicker();
try {
callback.finishedEvent(seq, true);
} catch (RemoteException e) {
}
return;
}
try {
if (DEBUG) Log.v(TAG,"InputMethodManager class " + "DISPATCH KEY: " + mCurMethod);
Log.d(TAG,"InputMethodManager class " + " dispatchKeyEvent method, IInputMethodSession mCurMethod dispatchKeyEvent");
mCurMethod.dispatchKeyEvent(seq, key, callback);
} catch (RemoteException e) {
Log.w(TAG,"InputMethodManager class " + "IME died: " + mCurId + " dropping: " + key, e);
try {
callback.finishedEvent(seq, false);
} catch (RemoteException ex) {
}
}
}
}
相应的日志如下:
01-01 10:48:36.010 D/PateoInputMethod( 2208): InputMethodManager class dispatchKeyEvent
01-01 10:48:36.010 V/PateoInputMethod( 2208): InputMethodManager class DISPATCH KEY: com.android.internal.view.IInputMethodSession$Stub$Proxy@420ce8e0
01-01 10:48:36.010 D/PateoInputMethod( 2208): InputMethodManager class dispatchKeyEvent method, IInputMethodSession mCurMethod dispatchKeyEvent
从日志来看调用了如下方法:
mCurMethod.dispatchKeyEvent(seq, key, callback);
/**
* The actual instance of the method to make calls on it.
*/
IInputMethodSession mCurMethod;
那么这个mCurMethod什么时候初始化的呢?见下面:
mCurMethod = res.method
InputBindResult res;
我们来看看这个InputBindResult,代码如下:
public final class InputBindResult implements Parcelable {
static final String TAG = "InputBindResult";
/**
* The input method service.
*/
public final IInputMethodSession method;
我们再来看一下,我grep的结果:
pateo@pateo-B86N53X:/work/project/a1001eh/frameworks/base$ grep -r "IInputMethodSession.Stub" ./
./core/java/android/inputmethodservice/IInputMethodSessionWrapper.java:class IInputMethodSessionWrapper extends IInputMethodSession.Stub
./core/java/com/android/internal/view/InputBindResult.java: method = IInputMethodSession.Stub.asInterface(source.readStrongBinder());
原来mCurMethod是在InputBindResult的构造方法里面被赋值的,代码如下:
InputBindResult(Parcel source) {
method = IInputMethodSession.Stub.asInterface(source.readStrongBinder());
id = source.readString();
sequence = source.readInt();
}
从上面我们还能看出IInputMethodSessionWrapper extends IInputMethodSession.Stub,好吧,我们回到如下的方法进入:
mCurMethod.dispatchKeyEvent(seq, key, callback);
即为如下的IInputMethodSessionWrapper中的dispatchKeyEvent方法,代码如下:
public void dispatchKeyEvent(int seq, KeyEvent event, IInputMethodCallback callback) {
mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_DISPATCH_KEY_EVENT, seq,
event, callback));
}
case DO_DISPATCH_KEY_EVENT: {
HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
mInputMethodSession.dispatchKeyEvent(msg.arg1,
(KeyEvent)args.arg1,
new InputMethodEventCallbackWrapper(
(IInputMethodCallback)args.arg2));
mCaller.recycleArgs(args);
return;
}
这里的mInputMethodSession怎么被赋值的呢?
public IInputMethodSessionWrapper(Context context,
InputMethodSession inputMethodSession) {
mCaller = new HandlerCaller(context, this);
mInputMethodSession = inputMethodSession;
}
继续跟踪,上面的方法在哪里被调用:
static class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback {
final Context mContext;
final IInputMethodCallback mCb;
InputMethodSessionCallbackWrapper(Context context, IInputMethodCallback cb) {
mContext = context;
mCb = cb;
}
public void sessionCreated(InputMethodSession session) {
try {
if (session != null) {
IInputMethodSessionWrapper wrap =
new IInputMethodSessionWrapper(mContext, session);
mCb.sessionCreated(wrap);
} else {
mCb.sessionCreated(null);
}
} catch (RemoteException e) {
}
}
}
public abstract class AbstractInputMethodService extends Service
implements KeyEvent.Callback {
private InputMethod mInputMethod;
final KeyEvent.DispatcherState mDispatcherState
= new KeyEvent.DispatcherState();
/**
* Base class for derived classes to implement their {@link InputMethod}
* interface. This takes care of basic maintenance of the input method,
* but most behavior must be implemented in a derived class.
*/
public abstract class AbstractInputMethodImpl implements InputMethod {
/**
* Instantiate a new client session for the input method, by calling
* back to {@link AbstractInputMethodService#onCreateInputMethodSessionInterface()
* AbstractInputMethodService.onCreateInputMethodSessionInterface()}.
*/
public void createSession(SessionCallback callback) {
callback.sessionCreated(onCreateInputMethodSessionInterface());
}
/**
* Called by the framework when a new InputMethodSession interface is
* needed for a new client of the input method.
*/
public abstract AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
public class InputMethodImpl extends AbstractInputMethodImpl {
@Override
public AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface() {
return new InputMethodSessionImpl();
}
好吧,我们回到msg里面的方法,上面的AbstractInputMethodService类中有如下代码:
public abstract class AbstractInputMethodSessionImpl implements InputMethodSession {
最最重要的代码如下:
public class InputMethodSessionImpl extends AbstractInputMethodSessionImpl {
而InputMethodSessionImpl这个类是在InputMethodService类中的,所以可以直接调用InputMethodService中的方法,如下展示了给你看下提供了大致几个方法: public class InputMethodSessionImpl extends AbstractInputMethodSessionImpl {
public void finishInput() {
if (!isEnabled()) {
return;
}
if (DEBUG) Log.v(TAG,"InputMethodService class" + "finishInput() in " + this);
doFinishInput();
}
/**
* Call {@link InputMethodService#onDisplayCompletions
* InputMethodService.onDisplayCompletions()}.
*/
public void displayCompletions(CompletionInfo[] completions) {
if (!isEnabled()) {
return;
}
mCurCompletions = completions;
onDisplayCompletions(completions);
}
/**
* Call {@link InputMethodService#onUpdateExtractedText
* InputMethodService.onUpdateExtractedText()}.
*/
public void updateExtractedText(int token, ExtractedText text) {
if (!isEnabled()) {
return;
}
onUpdateExtractedText(token, text);
}
/**
* Call {@link InputMethodService#onUpdateSelection
* InputMethodService.onUpdateSelection()}.
*/
public void updateSelection(int oldSelStart, int oldSelEnd,
int newSelStart, int newSelEnd,
int candidatesStart, int candidatesEnd) {
if (!isEnabled()) {
return;
}
InputMethodService.this.onUpdateSelection(oldSelStart, oldSelEnd,
newSelStart, newSelEnd, candidatesStart, candidatesEnd);
}
@Override
public void viewClicked(boolean focusChanged) {
Log.d(TAG, "viewClicked focusChanged=" + focusChanged);
if (!isEnabled()) {
Log.d(TAG, "viewClicked isEnabled false");
return;
}
InputMethodService.this.onViewClicked(focusChanged);
}
/**
* Call {@link InputMethodService#onUpdateCursor
* InputMethodService.onUpdateCursor()}.
*/
public void updateCursor(Rect newCursor) {
if (!isEnabled()) {
return;
}
InputMethodService.this.onUpdateCursor(newCursor);
}
/**
* Call {@link InputMethodService#onAppPrivateCommand
* InputMethodService.onAppPrivateCommand()}.
*/
public void appPrivateCommand(String action, Bundle data) {
if (!isEnabled()) {
return;
}
InputMethodService.this.onAppPrivateCommand(action, data);
}
/**
*
*/
public void toggleSoftInput(int showFlags, int hideFlags) {
InputMethodService.this.onToggleSoftInput(showFlags, hideFlags);
}
}
当然,我们的back键调用的方法dispatchKeyEvent没有被子类InputMethodSessionImpl中重写,而是直接在AbstractInputMethodSessionImpl中就被实现了来看看吧
/**
* Take care of dispatching incoming key events to the appropriate
* callbacks on the service, and tell the client when this is done.
*/
public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) {
boolean handled = event.dispatch(AbstractInputMethodService.this,
mDispatcherState, this);
if (callback != null) {
callback.finishedEvent(seq, handled);
}
}
进入上面的dispatch方法,进入该方法:
public final boolean dispatch(Callback receiver, DispatcherState state,
Object target) {
switch (mAction) {
case ACTION_DOWN: {
mFlags &= ~FLAG_START_TRACKING;
if (DEBUG) Log.v(TAG, "Key down to " + target + " in " + state
+ ": " + this);
boolean res = receiver.onKeyDown(mKeyCode, this);
这里可以看出,它回调了onKeyDown方法,好吧,我们继续进入AbstractInputMethodService.this的onKeyDown方法:
真实的onKeyDown是由其它的继承的子类实现的,即调用了InputMethodService中的onKeyDown方法,代码如下:
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
if (handleBack(false)) {
event.startTracking();
return true;
}
return false;
}
return doMovementKey(keyCode, event, MOVEMENT_DOWN);
}
最终调用了handleBack,代码如下:
private boolean handleBack(boolean doIt) {
if (mShowInputRequested) {
if (isExtractViewShown() && mExtractView instanceof ExtractEditLayout) {
ExtractEditLayout extractEditLayout = (ExtractEditLayout) mExtractView;
if (extractEditLayout.isActionModeStarted()) {
if (doIt) extractEditLayout.finishActionMode();
return true;
}
}
// If the soft input area is shown, back closes it and we
// consume the back key.
if (doIt) requestHideSelf(0);
即近一步调用了
// If the soft input area is shown, back closes it and we
// consume the back key.
if (doIt) requestHideSelf(0);
public void requestHideSelf(int flags) {
mImm.hideSoftInputFromInputMethod(mToken, flags);
}
上面的mImm定义:
InputMethodManager mImm;
最后还是回到了InputMethodManager,但是从上面我们可以看出:InputMethodManager 通过 IInputMethodSession访问InputMethodService