在TextView方法中,如下:
@Override
public boolean onTouchEvent(MotionEvent event) {
if (touchIsFinished && (isTextEditable() || mTextIsSelectable)) {
// Show the IME, except when selecting in read-only text.
final InputMethodManager imm = InputMethodManager.peekInstance();
Log.d(TAG, "TextView class onTouchEvent method viewClicked");
viewClicked(imm);
if (!mTextIsSelectable && mSoftInputShownOnFocus) {
Log.d(TAG, "TextView class onTouchEvent method && InputMethodManager showSoftInput" );
handled |= imm != null && imm.showSoftInput(this, 0);
}
}
当点击后,会打印如下日志:TextView class onTouchEvent method && InputMethodManager showSoftInput,在这之前会先进行viewClicked(imm),进入该方法:
/**
* @hide
*/
protected void viewClicked(InputMethodManager imm) {
if (imm != null) {
Log.d(TAG, "TextView class viewClicked method InputMethodManager viewClicked");
imm.viewClicked(this);
}
}
即调用imm的viewClicked方法:
/**
* Notify the event when the user tapped or clicked the text view.
*/
public void viewClicked(View view) {
final boolean focusChanged = mServedView != mNextServedView;
checkFocus();
synchronized (mH) {
if ((mServedView != view && (mServedView == null
|| !mServedView.checkInputConnectionProxy(view)))
|| mCurrentTextBoxAttribute == null || mCurMethod == null) {
return;
}
try {
if (DEBUG) Log.v(TAG,"InputMethodManager class " + "onViewClicked: " + focusChanged);
mCurMethod.viewClicked(focusChanged);
} catch (RemoteException e) {
Log.w(TAG,"InputMethodManager class " + "IME died: " + mCurId, e);
}
}
}
@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);
}
通过日志:InputMethodManager class onViewClicked: false来看,focusChanged为false,当前的mCurMethod为InputMethodService,所以我们进入到如下
return mService.showSoftInput(mClient, flags, resultReceiver);
这里的mService是InputMethodManagerService 【注意点一】,进入到如下:
@Override
public boolean showSoftInput(IInputMethodClient client, int flags,
ResultReceiver resultReceiver) {
Slog.d(TAG,"InputMethodManagerService class showSoftInput method ");
int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
synchronized (mMethodMap) {
if (mCurClient == null || client == null
|| mCurClient.client.asBinder() != client.asBinder()) {
try {
// We need to check if this is the current client with
// focus in the window manager, to allow this call to
// be made before input is started in it.
if (!mIWindowManager.inputMethodClientHasFocus(client)) {
Slog.w(TAG, "InputMethodManagerService class" + "Ignoring showSoftInput of uid " + uid + ": " + client);
return false;
}
} catch (RemoteException e) {
return false;
}
}
if (DEBUG) Slog.v(TAG, "InputMethodManagerService class" + "Client requesting input be shown");
return showCurrentInputLocked(flags, resultReceiver);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
打印了如下两行日志:
04-24 15:38:46.160 D/PateoInputMethod( 1221): InputMethodManagerService class showSoftInput method
04-24 15:38:46.160 V/PateoInputMethod( 1221): InputMethodManagerService classClient requesting input be shown
进入showCurrentInputLocked方法,如下:
boolean showCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
Slog.d(TAG,"InputMethodManagerService class showCurrentInputLocked method ");
mShowRequested = true;
if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
mShowExplicitlyRequested = true;
}
if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
mShowExplicitlyRequested = true;
mShowForced = true;
}
if (!mSystemReady) {
return false;
}
boolean res = false;
if (mCurMethod != null) {
Slog.d(TAG,"InputMethodManagerService class executeOrSendMessage method mCurMethod=" + mCurMethod.getClass().getName());
executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod,
resultReceiver));
mInputShown = true;
if (mHaveConnection && !mVisibleBound) {
mContext.bindService(mCurIntent, mVisibleConnection, Context.BIND_AUTO_CREATE);
mVisibleBound = true;
}
res = true;
相应的日志:
04-24 15:38:46.160 D/PateoInputMethod( 1221): InputMethodManagerService class showCurrentInputLocked method
04-24 15:38:46.160 D/PateoInputMethod( 1221): InputMethodManagerService class executeOrSendMessage method mCurMethod=com.android.internal.view.IInputMethod$Stub$Proxy
从日志来看是走入了如下代码:
executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod,
resultReceiver));
public Message obtainMessageIOO(int what, int arg1, Object arg2, Object arg3) {
SomeArgs args = obtainArgs();
args.arg1 = arg2;
args.arg2 = arg3;
return mH.obtainMessage(what, arg1, 0, args);
}
这里需要说明下,mCurMethod这个变量是InputMethodService【注意点二】,这个mCurMethod被封装到消息msg中了,后续执行消息的时候需要去除这个对象调用相应的方法:
case MSG_SHOW_SOFT_INPUT:
Slog.d(TAG,"InputMethodManagerService class MSG_SHOW_SOFT_INPUT msg ");
args = (HandlerCaller.SomeArgs)msg.obj;
try {
((IInputMethod)args.arg1).showSoftInput(msg.arg1,
(ResultReceiver)args.arg2);
} catch (RemoteException e) {
}
从上面看很明显,之前的mCurMethod对象即为msg.arg1,现在调用mCurMethod的showSoftInput方法,即调用InputMethodService的如下方法
/**
* Handle a request by the system to show the soft input area.
*/
public void showSoftInput(int flags, ResultReceiver resultReceiver) {
if (DEBUG) Log.v(TAG,"InputMethodService class" + "showSoftInput()");
boolean wasVis = isInputViewShown();
mShowInputFlags = 0;
if (onShowInputRequested(flags, false)) {
showWindow(true);
}
// If user uses hard keyboard, IME button should always be shown.
boolean showing = onEvaluateInputViewShown();
mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0),
mBackDisposition);
if (resultReceiver != null) {
resultReceiver.send(wasVis != isInputViewShown()
? InputMethodManager.RESULT_SHOWN
: (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
: InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
}
从上面来看mImm为InputMethodManager,即InputMethodService也有这么一个属性对象InputMethodService,还有上面的方法showSoftInput是在InputMethodService的内部类 public class InputMethodImpl extends AbstractInputMethodImpl 中的,跟踪一下:
public abstract class AbstractInputMethodImpl implements InputMethod ,AbstractInputMethodService是抽象类,InputMethodService集成于AbstractInputMethodImpl,其次public interface InputMethod
到现在基本清晰一点了,但是上面有几个对象变量是直接说明的,它们又是什么时候初始化的呢?需要进一步跟踪,即如下:
InputMethodManager类中的mService是InputMethodManagerService 【注意点一】
它的定义: final IInputMethodManager mService;
我进行了grep下,寻找相应的aidl对应骨架代理类
pateo@pateo-B86N53X:/work/project/a1001eh/frameworks/base/services/java$ grep -r "IInputMethodManager.Stub" ./
./com/android/server/InputMethodManagerService.java:public class InputMethodManagerService extends IInputMethodManager.Stub
现在明白了吧,但是这个mService又是什么时候初始化的呢?如下:
InputMethodManager(IInputMethodManager service, Looper looper) {
mService = service;
mMainLooper = looper;
mH = new H(looper);
mIInputContext = new ControlledInputConnectionWrapper(looper,
mDummyInputConnection, this);
if (mInstance == null) {
mInstance = this;
}
}
跟踪其在哪里被调用的?原来在它的单例的构造获取方法中
/**
* Internally, the input method manager can't be context-dependent, so
* we have this here for the places that need it.
* @hide
*/
static public InputMethodManager getInstance(Looper mainLooper) {
synchronized (mInstanceSync) {
if (mInstance != null) {
return mInstance;
}
IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
mInstance = new InputMethodManager(service, mainLooper);
}
return mInstance;
}
奥,原来是之前就被注册了,我们进入到SystemServer中去找一下,在SystemServer类的内部ServerThread线程的run中:
try {
Slog.i(TAG, "Input Method Service");
imm = new InputMethodManagerService(context);
ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
} catch (Throwable e) {
reportWtf("starting Input Manager Service", e);
}
这个先到这里,我们再看 :mCurMethod这个变量是InputMethodService【注意点二】
即InputMethodManagerService类中的mCurMethod,如下定义:
/**
* If non-null, this is the input method service we are currently connected
* to.
*/
IInputMethod mCurMethod;
它又是在哪里被初始化的呢?
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mMethodMap) {
if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
mCurMethod = IInputMethod.Stub.asInterface(service);
我进行了grep ,我们来看一下:
pateo@pateo-B86N53X:/work/project/a1001eh/frameworks/base$ grep -r "IInputMethod.Stub" ./
./core/java/android/inputmethodservice/IInputMethodWrapper.java:class IInputMethodWrapper extends IInputMethod.Stub
./services/java/com/android/server/InputMethodManagerService.java: mCurMethod = IInputMethod.Stub.asInterface(service);
好吧,我们来看一下IInputMethodWrapper?跟踪这个类在哪被初始化
@Override
final public IBinder onBind(Intent intent) {
if (mInputMethod == null) {
mInputMethod = onCreateInputMethodInterface();
}
return new IInputMethodWrapper(this, mInputMethod);
}
/**
* Called by the framework during initialization, when the InputMethod
* interface for this service needs to be created.
*/
public abstract AbstractInputMethodImpl onCreateInputMethodInterface();
上面这个方法在AbstractInputMethodService类中,而AbstractInputMethodService这个类是这样的关系如下:
public class InputMethodService extends AbstractInputMethodService
现在明白了吧?我们回到上面,如下:
case MSG_SHOW_SOFT_INPUT:
Slog.d(TAG,"InputMethodManagerService class MSG_SHOW_SOFT_INPUT msg ");
args = (HandlerCaller.SomeArgs)msg.obj;
try {
((IInputMethod)args.arg1).showSoftInput(msg.arg1,
(ResultReceiver)args.arg2);
} catch (RemoteException e) {
}
我们看到IInputMethodWrapper的showSoftInput的方法:
public void showSoftInput(int flags, ResultReceiver resultReceiver) {
mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_SHOW_SOFT_INPUT,
flags, resultReceiver));
}
而上面这个DO_SHOW_SOFT_INPUT消息又是做了什么?
case DO_SHOW_SOFT_INPUT:
inputMethod.showSoftInput(msg.arg1, (ResultReceiver)msg.obj);
这个inputMethod哪里来的呢?
public void executeMessage(Message msg) {
InputMethod inputMethod = mInputMethod.get();
跟踪mInputMethod这个又是哪里初始化的?
public IInputMethodWrapper(AbstractInputMethodService context,
InputMethod inputMethod) {
mTarget = new WeakReference<AbstractInputMethodService>(context);
mCaller = new HandlerCaller(context.getApplicationContext(), this);
mInputMethod = new WeakReference<InputMethod>(inputMethod);
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
}
看到上面明白了吧,构造函数里面赋值的,不就是上面之前分析的:
@Override
final public IBinder onBind(Intent intent) {
if (mInputMethod == null) {
mInputMethod = onCreateInputMethodInterface();
}
return new IInputMethodWrapper(this, mInputMethod);
}
现在你应该能明白了