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

Commit a975bfc4 authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Introduce InputMethodServiceInternal for better abstraction

This is a mechanical refactoring CL that has no behavior change.

This CL removes the direct dependency on AbstractInputMethodService
from whenever possible.  As a result, the following classes no longer
directly depend on AbstractInputMethodService.

 * android.inputmethodservice.IInputMethodWrapper
 * android.inputmethodservice.RemoteInputConnection
 * com.android.internal.inputmethod.ImeTracing
 * com.android.internal.inputmethod.ImeTracingClientImpl
 * com.android.internal.inputmethod.ImeTracingServerImpl

This is still a purely mechanical refactoring.  There should be no
observable behavior change.

Bug: 192412909
Test: atest CtsInputMethodTestCases
Test: Manually verified that IME tracing still works
Change-Id: I2aeeeacd27195ce10059d6590e098a4a969e774d
parent 26b594af
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