Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 00ec9a6d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Introduce InputMethodServiceInternal for better abstraction"

parents 0edf7f6f a975bfc4
Loading
Loading
Loading
Loading
+29 −44
Original line number Diff line number Diff line
@@ -25,13 +25,10 @@ import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSession;
import android.window.WindowProviderService;
@@ -215,16 +212,6 @@ public abstract class AbstractInputMethodService extends WindowProviderService
     */
    public abstract AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();

    /**
     * Dumps the internal state of IME to a protocol buffer output stream.
     *
     * @param proto ProtoOutputStream to dump data to.
     * @param icProto {@link InputConnection} call data in proto format.
     * @hide
     */
    @SuppressWarnings("HiddenAbstractMethod")
    public abstract void dumpProtoInternal(ProtoOutputStream proto, @Nullable byte[] icProto);

    /**
     * Implement this to handle {@link android.os.Binder#dump Binder.dump()}
     * calls on your input method.
@@ -238,7 +225,34 @@ public abstract class AbstractInputMethodService extends WindowProviderService
        if (mInputMethod == null) {
            mInputMethod = onCreateInputMethodInterface();
        }
        return new IInputMethodWrapper(this, mInputMethod);
        return new IInputMethodWrapper(createInputMethodServiceInternal(), mInputMethod);
    }

    /**
     * Used to inject custom {@link InputMethodServiceInternal}.
     *
     * @return the {@link InputMethodServiceInternal} to be used.
     */
    @NonNull
    InputMethodServiceInternal createInputMethodServiceInternal() {
        return new InputMethodServiceInternal() {
            /**
             * {@inheritDoc}
             */
            @NonNull
            @Override
            public Context getContext() {
                return AbstractInputMethodService.this;
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
                AbstractInputMethodService.this.dump(fd, fout, args);
            }
        };
    }

    /**
@@ -263,35 +277,6 @@ public abstract class AbstractInputMethodService extends WindowProviderService
        return false;
    }

    /**
     * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
     * permission to the content.
     *
     * <p>Default implementation does nothing.</p>
     *
     * @param inputContentInfo Content to be temporarily exposed from the input method to the
     * application.
     * This cannot be {@code null}.
     * @param inputConnection {@link InputConnection} with which
     * {@link InputConnection#commitContent(InputContentInfo, int, android.os.Bundle)} will be
     * called.
     * @return {@code false} if we cannot allow a temporary access permission.
     * @hide
     */
    public void exposeContent(@NonNull InputContentInfo inputContentInfo,
            @NonNull InputConnection inputConnection) {
        return;
    }

    /**
     * Called when the user took some actions that should be taken into consideration to update the
     * MRU list for input method rotation.
     *
     * @hide
     */
    public void notifyUserActionIfNecessary() {
    }

    // TODO(b/149463653): remove it in T. We missed the API deadline in S.
    /** @hide */
    @Override
+8 −8
Original line number Diff line number Diff line
@@ -76,7 +76,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
    private static final int DO_CHANGE_INPUTMETHOD_SUBTYPE = 80;
    private static final int DO_CREATE_INLINE_SUGGESTIONS_REQUEST = 90;

    final WeakReference<AbstractInputMethodService> mTarget;
    final WeakReference<InputMethodServiceInternal> mTarget;
    final Context mContext;
    @UnsupportedAppUsage
    final HandlerCaller mCaller;
@@ -129,12 +129,12 @@ class IInputMethodWrapper extends IInputMethod.Stub
        }
    }

    public IInputMethodWrapper(AbstractInputMethodService context, InputMethod inputMethod) {
        mTarget = new WeakReference<>(context);
        mContext = context.getApplicationContext();
    IInputMethodWrapper(InputMethodServiceInternal imsInternal, InputMethod inputMethod) {
        mTarget = new WeakReference<>(imsInternal);
        mContext = imsInternal.getContext().getApplicationContext();
        mCaller = new HandlerCaller(mContext, null, this, true /*asyncHandler*/);
        mInputMethod = new WeakReference<>(inputMethod);
        mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
        mTargetSdkVersion = imsInternal.getContext().getApplicationInfo().targetSdkVersion;
    }

    @MainThread
@@ -149,7 +149,7 @@ class IInputMethodWrapper extends IInputMethod.Stub

        switch (msg.what) {
            case DO_DUMP: {
                AbstractInputMethodService target = mTarget.get();
                InputMethodServiceInternal target = mTarget.get();
                if (target == null) {
                    return;
                }
@@ -251,11 +251,11 @@ class IInputMethodWrapper extends IInputMethod.Stub
    @BinderThread
    @Override
    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
        AbstractInputMethodService target = mTarget.get();
        InputMethodServiceInternal target = mTarget.get();
        if (target == null) {
            return;
        }
        if (target.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
        if (target.getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                != PackageManager.PERMISSION_GRANTED) {
            
            fout.println("Permission Denial: can't dump InputMethodManager from from pid="
+128 −103
Original line number Diff line number Diff line
@@ -55,7 +55,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACK

import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.annotation.AnyThread;
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
@@ -740,7 +739,7 @@ public class InputMethodService extends AbstractInputMethodService {
                return;
            }
            ImeTracing.getInstance().triggerServiceDump(
                    "InputMethodService.InputMethodImpl#hideSoftInput", InputMethodService.this,
                    "InputMethodService.InputMethodImpl#hideSoftInput", mDumper,
                    null /* icProto */);
            final boolean wasVisible = isInputViewShown();
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput");
@@ -797,7 +796,7 @@ public class InputMethodService extends AbstractInputMethodService {
            }
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput");
            ImeTracing.getInstance().triggerServiceDump(
                    "InputMethodService.InputMethodImpl#showSoftInput", InputMethodService.this,
                    "InputMethodService.InputMethodImpl#showSoftInput", mDumper,
                    null /* icProto */);
            final boolean wasVisible = isInputViewShown();
            if (dispatchOnShowInputRequested(flags, false)) {
@@ -2222,7 +2221,7 @@ public class InputMethodService extends AbstractInputMethodService {
            return;
        }

        ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", this,
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", mDumper,
                null /* icProto */);
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow");
        mDecorViewWasVisible = mDecorViewVisible;
@@ -2301,7 +2300,7 @@ public class InputMethodService extends AbstractInputMethodService {
     */
    private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible) {
        ImeTracing.getInstance().triggerServiceDump(
                "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", this,
                "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", mDumper,
                null /* icProto */);
        if (setVisible) {
            cancelImeSurfaceRemoval();
@@ -2330,7 +2329,7 @@ public class InputMethodService extends AbstractInputMethodService {

    public void hideWindow() {
        if (DEBUG) Log.v(TAG, "CALL: hideWindow");
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", this,
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper,
                null /* icProto */);
        mWindowVisible = false;
        finishViews(false /* finishingInput */);
@@ -2403,7 +2402,7 @@ public class InputMethodService extends AbstractInputMethodService {
    
    void doFinishInput() {
        if (DEBUG) Log.v(TAG, "CALL: doFinishInput");
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#doFinishInput", this,
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#doFinishInput", mDumper,
                null /* icProto */);
        finishViews(true /* finishingInput */);
        if (mInputStarted) {
@@ -2420,7 +2419,7 @@ public class InputMethodService extends AbstractInputMethodService {
        if (!restarting && mInputStarted) {
            doFinishInput();
        }
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", this,
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", mDumper,
                null /* icProto */);
        mInputStarted = true;
        mStartedInputConnection = ic;
@@ -2580,7 +2579,7 @@ public class InputMethodService extends AbstractInputMethodService {
     * @param flags Provides additional operating flags.
     */
    public void requestHideSelf(int flags) {
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", this,
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", mDumper,
                null /* icProto */);
        mPrivOps.hideMySoftInput(flags);
    }
@@ -2594,7 +2593,7 @@ public class InputMethodService extends AbstractInputMethodService {
     * @param flags Provides additional operating flags.
     */
    public final void requestShowSelf(int flags) {
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", this,
        ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", mDumper,
                null /* icProto */);
        mPrivOps.showMySoftInput(flags);
    }
@@ -3281,18 +3280,28 @@ public class InputMethodService extends AbstractInputMethodService {
    }

    /**
     * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
     * permission to the content.
     * Used to inject custom {@link InputMethodServiceInternal}.
     *
     * @param inputContentInfo Content to be temporarily exposed from the input method to the
     * application.
     * This cannot be {@code null}.
     * @param inputConnection {@link InputConnection} with which
     * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} will be called.
     * @hide
     * @return the {@link InputMethodServiceInternal} to be used.
     */
    @NonNull
    @Override
    final InputMethodServiceInternal createInputMethodServiceInternal() {
        return new InputMethodServiceInternal() {
            /**
             * {@inheritDoc}
             */
            @NonNull
            @Override
            public Context getContext() {
                return InputMethodService.this;
            }

            /**
             * {@inheritDoc}
             */
            @Override
    public final void exposeContent(@NonNull InputContentInfo inputContentInfo,
            public void exposeContent(@NonNull InputContentInfo inputContentInfo,
                    @NonNull InputConnection inputConnection) {
                if (inputConnection == null) {
                    return;
@@ -3305,11 +3314,9 @@ public class InputMethodService extends AbstractInputMethodService {

            /**
             * {@inheritDoc}
     * @hide
             */
    @AnyThread
            @Override
    public final void notifyUserActionIfNecessary() {
            public void notifyUserActionIfNecessary() {
                synchronized (mLock) {
                    if (mNotifyUserActionSent) {
                        return;
@@ -3323,12 +3330,10 @@ public class InputMethodService extends AbstractInputMethodService {
             * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
             * permission to the content.
             *
     * <p>See {@link android.inputmethodservice.InputMethodService#exposeContent(InputContentInfo,
     * InputConnection)} for details.</p>
             * <p>See {@link #exposeContent(InputContentInfo, InputConnection)} for details.</p>
             *
     * @param inputContentInfo Content to be temporarily exposed from the input method to the
     * application.
     * This cannot be {@code null}.
             * @param inputContentInfo Content to be temporarily exposed from the input method to
             *                         the application.  This cannot be {@code null}.
             * @param editorInfo The editor that receives {@link InputContentInfo}.
             */
            private void exposeContentInternal(@NonNull InputContentInfo inputContentInfo,
@@ -3337,13 +3342,31 @@ public class InputMethodService extends AbstractInputMethodService {
                final IInputContentUriToken uriToken =
                        mPrivOps.createInputContentUriToken(contentUri, editorInfo.packageName);
                if (uriToken == null) {
            Log.e(TAG, "createInputContentAccessToken failed. contentUri=" + contentUri.toString()
                    + " packageName=" + editorInfo.packageName);
                    Log.e(TAG, "createInputContentAccessToken failed. contentUri="
                            + contentUri.toString() + " packageName=" + editorInfo.packageName);
                    return;
                }
                inputContentInfo.setUriToken(uriToken);
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public void dump(FileDescriptor fd, PrintWriter fout, String[]args) {
                InputMethodService.this.dump(fd, fout, args);
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public void triggerServiceDump(String where, @Nullable byte[] icProto) {
                ImeTracing.getInstance().triggerServiceDump(where, mDumper, icProto);
            }
        };
    }

    private int mapToImeWindowStatus() {
        return IME_ACTIVE
                | (isInputViewShown() ? IME_VISIBLE : 0);
@@ -3411,11 +3434,12 @@ public class InputMethodService extends AbstractInputMethodService {
        p.println(" mSettingsObserver=" + mSettingsObserver);
    }

    private final ImeTracing.ServiceDumper mDumper = new ImeTracing.ServiceDumper() {
        /**
     * @hide
         * {@inheritDoc}
         */
        @Override
    public final void dumpProtoInternal(ProtoOutputStream proto, byte[] icProto) {
        public void dumpToProto(ProtoOutputStream proto, @Nullable byte[] icProto) {
            final long token = proto.start(InputMethodServiceTraceProto.INPUT_METHOD_SERVICE);
            mWindow.dumpDebug(proto, SOFT_INPUT_WINDOW);
            proto.write(VIEWS_CREATED, mViewsCreated);
@@ -3449,4 +3473,5 @@ public class InputMethodService extends AbstractInputMethodService {
            }
            proto.end(token);
        }
    };
}
+86 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.inputmethodservice;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.os.Bundle;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputContentInfo;

import java.io.FileDescriptor;
import java.io.PrintWriter;

/**
 * A set of internal methods exposed by {@link InputMethodService} to be called only from other
 * framework classes for internal use.
 *
 * <p>CAVEATS: {@link AbstractInputMethodService} does not support all the methods here.</p>
 */
interface InputMethodServiceInternal {
    /**
     * @return {@link Context} associated with the service.
     */
    @NonNull
    Context getContext();

    /**
     * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
     * permission to the content.
     *
     * @param inputContentInfo Content to be temporarily exposed from the input method to the
     *                         application. This cannot be {@code null}.
     * @param inputConnection {@link InputConnection} with which
     *                        {@link InputConnection#commitContent(InputContentInfo, int, Bundle)}
     *                        will be called.
     */
    default void exposeContent(@NonNull InputContentInfo inputContentInfo,
            @NonNull InputConnection inputConnection) {
    }

    /**
     * Called when the user took some actions that should be taken into consideration to update the
     * MRU list for input method rotation.
     */
    default void notifyUserActionIfNecessary() {
    }

    /**
     * Called when the system is asking the IME to dump its information for debugging.
     *
     * <p>The caller is responsible for checking {@link android.Manifest.permission.DUMP}.</p>
     *
     * @param fd The raw file descriptor that the dump is being sent to.
     * @param fout The file to which you should dump your state.  This will be
     * closed for you after you return.
     * @param args additional arguments to the dump request.
     */
    default void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
    }

    /**
     * Called with {@link com.android.internal.inputmethod.ImeTracing#triggerServiceDump(String,
     * com.android.internal.inputmethod.ImeTracing.ServiceDumper, byte[])} needs to be triggered
     * with the given parameters.
     *
     * @param where {@code where} parameter to be passed.
     * @param icProto {@code icProto} parameter to be passed.
     */
    default void triggerServiceDump(String where, @Nullable byte[] icProto) {
    }
}
+16 −22
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ final class RemoteInputConnection implements InputConnection {
    private final IInputContextInvoker mInvoker;

    @NonNull
    private final WeakReference<AbstractInputMethodService> mInputMethodService;
    private final WeakReference<InputMethodServiceInternal> mInputMethodService;

    @MissingMethodFlags
    private final int mMissingMethods;
@@ -67,7 +67,7 @@ final class RemoteInputConnection implements InputConnection {
    private final CancellationGroup mCancellationGroup;

    RemoteInputConnection(
            @NonNull WeakReference<AbstractInputMethodService> inputMethodService,
            @NonNull WeakReference<InputMethodServiceInternal> inputMethodService,
            IInputContext inputContext, @MissingMethodFlags int missingMethods,
            @NonNull CancellationGroup cancellationGroup) {
        mInputMethodService = inputMethodService;
@@ -90,12 +90,11 @@ final class RemoteInputConnection implements InputConnection {
        final CharSequence result = Completable.getResultOrNull(
                value, TAG, "getTextAfterCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);

        final AbstractInputMethodService inputMethodService = mInputMethodService.get();
        final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
        if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
            final byte[] icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(length,
                    flags, result);
            ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextAfterCursor",
                    inputMethodService, icProto);
            inputMethodService.triggerServiceDump(TAG + "#getTextAfterCursor", icProto);
        }

        return result;
@@ -115,12 +114,11 @@ final class RemoteInputConnection implements InputConnection {
        final CharSequence result = Completable.getResultOrNull(
                value, TAG, "getTextBeforeCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);

        final AbstractInputMethodService inputMethodService = mInputMethodService.get();
        final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
        if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
            final byte[] icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(length,
                    flags, result);
            ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextBeforeCursor",
                    inputMethodService, icProto);
            inputMethodService.triggerServiceDump(TAG + "#getTextBeforeCursor", icProto);
        }

        return result;
@@ -140,12 +138,11 @@ final class RemoteInputConnection implements InputConnection {
        final CharSequence result = Completable.getResultOrNull(
                value, TAG, "getSelectedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);

        final AbstractInputMethodService inputMethodService = mInputMethodService.get();
        final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
        if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
            final byte[] icProto = InputConnectionProtoDumper.buildGetSelectedTextProto(flags,
                    result);
            ImeTracing.getInstance().triggerServiceDump(TAG + "#getSelectedText",
                    inputMethodService, icProto);
            inputMethodService.triggerServiceDump(TAG + "#getSelectedText", icProto);
        }

        return result;
@@ -179,12 +176,11 @@ final class RemoteInputConnection implements InputConnection {
        final SurroundingText result = Completable.getResultOrNull(
                value, TAG, "getSurroundingText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);

        final AbstractInputMethodService inputMethodService = mInputMethodService.get();
        final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
        if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
            final byte[] icProto = InputConnectionProtoDumper.buildGetSurroundingTextProto(
                    beforeLength, afterLength, flags, result);
            ImeTracing.getInstance().triggerServiceDump(TAG + "#getSurroundingText",
                    inputMethodService, icProto);
            inputMethodService.triggerServiceDump(TAG + "#getSurroundingText", icProto);
        }

        return result;
@@ -200,12 +196,11 @@ final class RemoteInputConnection implements InputConnection {
        final int result = Completable.getResultOrZero(
                value, TAG, "getCursorCapsMode()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);

        final AbstractInputMethodService inputMethodService = mInputMethodService.get();
        final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
        if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
            final byte[] icProto = InputConnectionProtoDumper.buildGetCursorCapsModeProto(
                    reqModes, result);
            ImeTracing.getInstance().triggerServiceDump(TAG + "#getCursorCapsMode",
                    inputMethodService, icProto);
            inputMethodService.triggerServiceDump(TAG + "#getCursorCapsMode", icProto);
        }

        return result;
@@ -221,12 +216,11 @@ final class RemoteInputConnection implements InputConnection {
        final ExtractedText result = Completable.getResultOrNull(
                value, TAG, "getExtractedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);

        final AbstractInputMethodService inputMethodService = mInputMethodService.get();
        final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
        if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
            final byte[] icProto = InputConnectionProtoDumper.buildGetExtractedTextProto(
                    request, flags, result);
            ImeTracing.getInstance().triggerServiceDump(TAG + "#getExtractedText",
                    inputMethodService, icProto);
            inputMethodService.triggerServiceDump(TAG + "#getExtractedText", icProto);
        }

        return result;
@@ -243,7 +237,7 @@ final class RemoteInputConnection implements InputConnection {

    @AnyThread
    private void notifyUserActionIfNecessary() {
        final AbstractInputMethodService inputMethodService = mInputMethodService.get();
        final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
        if (inputMethodService == null) {
            // This basically should not happen, because it's the the caller of this method.
            return;
@@ -395,7 +389,7 @@ final class RemoteInputConnection implements InputConnection {
        }

        if ((flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
            final AbstractInputMethodService inputMethodService = mInputMethodService.get();
            final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
            if (inputMethodService == null) {
                // This basically should not happen, because it's the caller of this method.
                return false;
Loading