android 点击输入框调出输入法流程分析




在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);
    }

现在你应该能明白了







  















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值