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

<= 0) mCurSeq = 1;// 将新程序设置为当前活动的程序mCurClient = cs;mCurInputContext = inputContext;mCurInputContextMissingMethods = missingMethods;mCurAttribute = attribute;// Check if the input method is changing.if (mCurId != null && mCurId.equals(mCurMethodId)) {if (cs.curSession != null) {// Fast case: if we are already connected to the input method,// then just return it.// 连接已经建立,开始绑定return attachNewInputLocked((controlFlags&InputMethodManager.CONTROL_START_INITIAL) != 0);}if (mHaveConnection) {if (mCurMethod != null) {// 如果 输入法的连接 已经创建,直接传递给程序 client 端// Return to client, and we will get back with it when// we have had a session made for it.requestClientSessionLocked(cs);return new InputBindResult(null, null, mCurId, mCurSeq,mCurUserActionNotificationSequenceNumber);} else if (SystemClock.uptimeMillis()< (mLastBindTime+TIME_TO_RECONNECT)) {// In this case we have connected to the service, but// don't yet have its interface.If it hasn't been too// long since we did the connection, we'll return to// the client and wait to get the service interface so// we can report back.If it has been too long, we want// to fall through so we can try a disconnect/reconnect// to see if we can get back in touch with the service.return new InputBindResult(null, null, mCurId, mCurSeq,mCurUserActionNotificationSequenceNumber);} else {EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);}}}// 启动输入法并建立连接return startInputInnerLocked();}InputBindResult startInputInnerLocked() {if (mCurMethodId == null) {return mNoBinding;}if (!mSystemReady) {// If the system is not yet ready, we shouldn't be running third// party code.return new InputBindResult(null, null, mCurMethodId, mCurSeq,mCurUserActionNotificationSequenceNumber);}InputMethodInfo info = mMethodMap.get(mCurMethodId);if (info == null) {throw new IllegalArgumentException("Unknown id: " + mCurMethodId);}unbindCurrentMethodLocked(true);// 启动输入法ServicemCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);mCurIntent.setComponent(info.getComponent());mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,com.android.internal.R.string.input_method_binding_label);mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));if (bindCurrentInputMethodService(mCurIntent, this, Context.BIND_AUTO_CREATE| Context.BIND_NOT_VISIBLE | Context.BIND_NOT_FOREGROUND| Context.BIND_SHOWING_UI)) {mLastBindTime = SystemClock.uptimeMillis();mHaveConnection = true;mCurId = info.getId();// mCurToken 是给输入法Service 来绑定输入法window的// 通过 mCurToken ,InputMethodManagerService 直接管理 输入法windowmCurToken = new Binder();try {if (true || DEBUG) Slog.v(TAG, "Adding window token: " + mCurToken);mIWindowManager.addWindowToken(mCurToken,WindowManager.LayoutParams.TYPE_INPUT_METHOD);} catch (RemoteException e) {}return new InputBindResult(null, null, mCurId, mCurSeq,mCurUserActionNotificationSequenceNumber);} else {mCurIntent = null;Slog.w(TAG, "Failure connecting to input method service: "+ mCurIntent);}return null;}private boolean bindCurrentInputMethodService(Intent service, ServiceConnection conn, int flags) {if (service == null || conn == null) {Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn);return false;}return mContext.bindServiceAsUser(service, conn, flags,new UserHandle(mSettings.getCurrentUserId()));}// AbstractInputMethodService.java//输入法启动完成后就在函数onBind 传回一个binder接口 @Overridefinal public IBinder onBind(Intent intent) {if (mInputMethod == null) {mInputMethod = onCreateInputMethodInterface();}// IInputMethodWrapper 将 IMMS的调用转化为 message,// 然后在 message 线程调用 mInputMethod 对应的接口,// 实现输入法的异步处理return new IInputMethodWrapper(this, mInputMethod);}// InputMethodService.java/*** Implement to return our standard {@link InputMethodImpl}.Subclasses* can override to provide their own customized version.*/@Overridepublic AbstractInputMethodImpl onCreateInputMethodInterface() {return new InputMethodImpl();}// 由于IMMS是以bindService的方式启动输入法service,所以当输入法service启动完// 成后它就会回调IMMS的onServiceConnected// InputMethodManagerService.java@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {synchronized (mMethodMap) {if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {// 保存输入法Service 传递过来的 通信接口IInputMethodmCurMethod = IInputMethod.Stub.asInterface(service);if (mCurToken == null) {Slog.w(TAG, "Service connected without a token!");unbindCurrentMethodLocked(false);return;}if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);// 将刚刚创建的window token传递给输入法service,然后输入用这个token// 创建window,这样IMMS可以用根据这个token找到输入法在IMMS里// 的数据及输入法window在WMS里的数据executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(MSG_ATTACH_TOKEN, mCurMethod, mCurToken));if (mCurClient != null) {clearClientSessionLocked(mCurClient);// 请求为程序和输入法建立一个连接会话,这样client就可以直接和// 输入法通信了requestClientSessionLocked(mCurClient);}}}}case MSG_ATTACH_TOKEN:args = (SomeArgs)msg.obj;try {if (DEBUG) Slog.v(TAG, "Sending attach of token: " + args.arg2);// 和输入法通信((IInputMethod)args.arg1).attachToken((IBinder)args.arg2);} catch (RemoteException e) {}args.recycle();return true;