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

Commit 80498d55 authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Always send WindowToken when starting IME input

In InputMethodManagerService, windowGainedFocus() is a superset of
startInput().  If the window specified to windowGainedFocus() is
already seen in IMMS#mCurFocusedWindow, windowGainedFocus() just works
like startInput().  If the window specified to windowGainedFocus()
does not match to IMMS#mCurFocusedWindow, then it takes care of
everything we need to change the IME target window including tasks
that startInput() does.  The reason why we still have startInput() is
just because my previous CL [1], which unified windowGainedFocus() and
startInput() with keeping the existing behavior, did not intend to
change the existing behavior.

Now that we are going to enforce true traceability between input
session and target application window, IMMS#windowGainedFocus() is
what we want to always rely on.

Bug: 110531072
Test: atest CtsInputMethodTestCases CtsInputMethodServiceHostTestCases
Change-Id: I24feedf9ef5aca90ef947f4f2aa3e78365fd8c8a
parent 594c88f7
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -1239,7 +1239,7 @@ public final class InputMethodManager {
    }

    boolean startInputInner(@InputMethodClient.StartInputReason final int startInputReason,
            IBinder windowGainingFocus, int controlFlags, int softInputMode,
            @Nullable IBinder windowGainingFocus, int controlFlags, int softInputMode,
            int windowFlags) {
        final View view;
        synchronized (mH) {
@@ -1256,6 +1256,20 @@ public final class InputMethodManager {
            }
        }

        if (windowGainingFocus == null) {
            windowGainingFocus = view.getWindowToken();
            if (windowGainingFocus == null) {
                Log.e(TAG, "ABORT input: ServedView must be attached to a Window");
                return false;
            }
            controlFlags |= CONTROL_WINDOW_VIEW_HAS_FOCUS;
            if (view.onCheckIsTextEditor()) {
                controlFlags |= CONTROL_WINDOW_IS_TEXT_EDITOR;
            }
            softInputMode = view.getViewRootImpl().mWindowAttributes.softInputMode;
            windowFlags = view.getViewRootImpl().mWindowAttributes.flags;
        }

        // Now we need to get an input connection from the served view.
        // This is complicated in a couple ways: we can't be holding our lock
        // when calling out to the view, and we need to make sure we call into
+9 −85
Original line number Diff line number Diff line
@@ -1825,50 +1825,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                mCurId, mCurSeq, mCurUserActionNotificationSequenceNumber);
    }

    @GuardedBy("mMethodMap")
    @NonNull
    InputBindResult startInputLocked(
            /* @InputMethodClient.StartInputReason */ final int startInputReason,
            IInputMethodClient client, IInputContext inputContext,
            /* @InputConnectionInspector.missingMethods */ final int missingMethods,
            @Nullable EditorInfo attribute, int controlFlags) {
        // If no method is currently selected, do nothing.
        if (mCurMethodId == null) {
            return InputBindResult.NO_IME;
        }

        ClientState cs = mClients.get(client.asBinder());
        if (cs == null) {
            throw new IllegalArgumentException("unknown client "
                    + client.asBinder());
        }

        if (attribute == null) {
            Slog.w(TAG, "Ignoring startInput with null EditorInfo."
                    + " uid=" + cs.uid + " pid=" + cs.pid);
            return InputBindResult.NULL_EDITOR_INFO;
        }

        try {
            if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) {
                // Check with the window manager to make sure this client actually
                // has a window with focus.  If not, reject.  This is thread safe
                // because if the focus changes some time before or after, the
                // next client receiving focus that has any interest in input will
                // be calling through here after that change happens.
                if (DEBUG) {
                    Slog.w(TAG, "Starting input on non-focused client " + cs.client
                            + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
                }
                return InputBindResult.NOT_IME_TARGET_WINDOW;
            }
        } catch (RemoteException e) {
        }

        return startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
                controlFlags, startInputReason);
    }

    @GuardedBy("mMethodMap")
    @NonNull
    InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
@@ -1997,36 +1953,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        return InputBindResult.IME_NOT_CONNECTED;
    }

    @NonNull
    private InputBindResult startInput(
            /* @InputMethodClient.StartInputReason */ final int startInputReason,
            IInputMethodClient client, IInputContext inputContext,
            /* @InputConnectionInspector.missingMethods */ final int missingMethods,
            @Nullable EditorInfo attribute, int controlFlags) {
        if (!calledFromValidUser()) {
            return InputBindResult.INVALID_USER;
        }
        synchronized (mMethodMap) {
            if (DEBUG) {
                Slog.v(TAG, "startInput: reason="
                        + InputMethodClient.getStartInputReason(startInputReason)
                        + " client = " + client.asBinder()
                        + " inputContext=" + inputContext
                        + " missingMethods="
                        + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
                        + " attribute=" + attribute
                        + " controlFlags=#" + Integer.toHexString(controlFlags));
            }
            final long ident = Binder.clearCallingIdentity();
            try {
                return startInputLocked(startInputReason, client, inputContext, missingMethods,
                        attribute, controlFlags);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    }

    @Override
    public void finishInput(IInputMethodClient client) {
    }
@@ -2741,15 +2667,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
            /* @InputConnectionInspector.missingMethods */ final int missingMethods,
            int unverifiedTargetSdkVersion) {
        final InputBindResult result;
        if (windowToken != null) {
            result = windowGainedFocus(startInputReason, client, windowToken, controlFlags,
                    softInputMode, windowFlags, attribute, inputContext, missingMethods,
                    unverifiedTargetSdkVersion);
        } else {
            result = startInput(startInputReason, client, inputContext, missingMethods, attribute,
                    controlFlags);
        if (windowToken == null) {
            Slog.e(TAG, "windowToken cannot be null.");
            return InputBindResult.NULL;
        }
        final InputBindResult result = startInputOrWindowGainedFocusInternal(startInputReason,
                client, windowToken, controlFlags, softInputMode, windowFlags, attribute,
                inputContext, missingMethods, unverifiedTargetSdkVersion);
        if (result == null) {
            // This must never happen, but just in case.
            Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
@@ -2762,9 +2686,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
    }

    @NonNull
    private InputBindResult windowGainedFocus(
    private InputBindResult startInputOrWindowGainedFocusInternal(
            /* @InputMethodClient.StartInputReason */ final int startInputReason,
            IInputMethodClient client, IBinder windowToken, int controlFlags,
            IInputMethodClient client, @NonNull IBinder windowToken, int controlFlags,
            /* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
            int windowFlags, EditorInfo attribute, IInputContext inputContext,
            /* @InputConnectionInspector.missingMethods */  final int missingMethods,
@@ -2775,7 +2699,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        long ident = Binder.clearCallingIdentity();
        try {
            synchronized (mMethodMap) {
                if (DEBUG) Slog.v(TAG, "windowGainedFocus: reason="
                if (DEBUG) Slog.v(TAG, "startInputOrWindowGainedFocusInternal: reason="
                        + InputMethodClient.getStartInputReason(startInputReason)
                        + " client=" + client.asBinder()
                        + " inputContext=" + inputContext