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

Commit a24622cf authored by Adrian Roos's avatar Adrian Roos
Browse files

Fix hiding keyboard animation stuck while dialog dismissing.

When dismissing a dialog with EditText focused and keyboard shown,
the keyboard does not get correctly dismissed.

This happens because after CL[1] landed, returning to the  activity won't start
new input connection, and the activity will thus not regain control over
the IME.

This fix restores the previous behavior, where  IMM will start a fake input
connection even without an editor.

[1]: I1ef3d341af9d473d94d52fd1890deafbae2bc9e1

Fix: 161273049
Test: atest CtsInputMethodTestCases
Test: manual as follows
     0) Have some files downloaded in the device
     1) Launch Files app > Browse > Click Internal Storage
     2) Long press on any file > From menu, click "Rename"
     3) Enter some name with soft keyboard and click "OK"
     4) Expect Keyboard should hide

Change-Id: I022ad658844142ff4a4cf3b91953013f2bfbb58a
parent 7368ed7d
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -125,10 +125,10 @@ public final class ImeFocusController {
        final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView;
        onViewFocusChanged(viewForWindowFocus, true);

        // Starting new input when the next focused view is same as served view but the
        // editor is not aligned with the same editor or editor is inactive.
        final boolean nextFocusIsServedView = mServedView != null && mServedView == focusedView;
        if (nextFocusIsServedView && !immDelegate.isSameEditorAndAcceptingText(focusedView)) {
        // Starting new input when the next focused view is same as served view but the currently
        // active connection (if any) is not associated with it.
        final boolean nextFocusIsServedView = mServedView == viewForWindowFocus;
        if (nextFocusIsServedView && !immDelegate.hasActiveConnection(viewForWindowFocus)) {
            forceFocus = true;
        }

@@ -254,7 +254,7 @@ public final class ImeFocusController {
        void setCurrentRootView(ViewRootImpl rootView);
        boolean isCurrentRootView(ViewRootImpl rootView);
        boolean isRestartOnNextWindowFocus(boolean reset);
        boolean isSameEditorAndAcceptingText(View view);
        boolean hasActiveConnection(View view);
    }

    public View getServedView() {
+26 −31
Original line number Diff line number Diff line
@@ -19,8 +19,8 @@ package android.view.inputmethod;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;

import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR;
import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR;
import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION;

import android.annotation.DrawableRes;
import android.annotation.NonNull;
@@ -89,6 +89,7 @@ import com.android.internal.view.InputBindResult;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collections;
@@ -610,14 +611,13 @@ public final class InputMethodManager {
        @Override
        public void startInputAsyncOnWindowFocusGain(View focusedView,
                @SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus) {
            final boolean forceNewFocus1 = forceNewFocus;
            final int startInputFlags = getStartInputFlags(focusedView, 0);

            final ImeFocusController controller = getFocusController();
            if (controller == null) {
                return;
            }
            if (controller.checkFocus(forceNewFocus1, false)) {
            if (controller.checkFocus(forceNewFocus, false)) {
                // We need to restart input on the current focus view.  This
                // should be done in conjunction with telling the system service
                // about the window gaining focus, to help make the transition
@@ -633,15 +633,15 @@ public final class InputMethodManager {
                // we'll just do a window focus gain and call it a day.
                try {
                    View servedView = controller.getServedView();
                    boolean nextFocusSameEditor = servedView != null && servedView == focusedView
                            && isSameEditorAndAcceptingText(focusedView);
                    boolean nextFocusHasConnection = servedView != null && servedView == focusedView
                            && hasActiveConnection(focusedView);
                    if (DEBUG) {
                        Log.v(TAG, "Reporting focus gain, without startInput"
                                + ", nextFocusIsServedView=" + nextFocusSameEditor);
                                + ", nextFocusIsServedView=" + nextFocusHasConnection);
                    }
                    final int startInputReason =
                            nextFocusSameEditor ? WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR
                                    : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR;
                            nextFocusHasConnection ? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION
                                    : WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
                    mService.startInputOrWindowGainedFocus(
                            startInputReason, mClient,
                            focusedView.getWindowToken(), startInputFlags, softInputMode,
@@ -701,33 +701,24 @@ public final class InputMethodManager {
        }

        /**
         * For {@link ImeFocusController} to check if the given focused view aligns with the same
         * editor and the editor is active to accept the text input.
         * Checks whether the active input connection (if any) is for the given view.
         *
         * TODO(b/160968797): Remove this method and move mCurrentTextBoxAttritube to
         * TODO(b/160968797): Remove this method and move mServedInputConnectionWrapper to
         *  ImeFocusController.
         * In the long-term, we should make mCurrentTextBoxAtrtribue as per-window base instance,
         * so that we we can directly check if the current focused view aligned with the same editor
         * in the window without using this checking.
         *
         * Note that this method is only use for fixing start new input may ignored issue
         * Note that this method is only intended for restarting input after focus gain
         * (e.g. b/160391516), DO NOT leverage this method to do another check.
         */
        public boolean isSameEditorAndAcceptingText(View view) {
        @Override
        public boolean hasActiveConnection(View view) {
            synchronized (mH) {
                if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null) {
                if (!hasServedByInputMethodLocked(view)) {
                    return false;
                }

                final EditorInfo ic = mCurrentTextBoxAttribute;
                // This sameEditor checking is based on using object hash comparison to check if
                // some fields of the current EditorInfo (e.g. autoFillId, OpPackageName) the
                // hash code is same as the given focused view.
                final boolean sameEditor = view.onCheckIsTextEditor() && view.getId() == ic.fieldId
                        && view.getAutofillId() == ic.autofillId
                        && view.getContext().getOpPackageName() == ic.packageName;
                return sameEditor && mServedInputConnectionWrapper != null
                        && mServedInputConnectionWrapper.isActive();
                return mServedInputConnectionWrapper != null
                        && mServedInputConnectionWrapper.isActive()
                        && mServedInputConnectionWrapper.mServedView.get() == view;
            }
        }
    }
@@ -980,11 +971,13 @@ public final class InputMethodManager {

    private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
        private final InputMethodManager mParentInputMethodManager;
        private final WeakReference<View> mServedView;

        public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn,
                final InputMethodManager inputMethodManager) {
        ControlledInputConnectionWrapper(Looper mainLooper, InputConnection conn,
                InputMethodManager inputMethodManager, View servedView) {
            super(mainLooper, conn);
            mParentInputMethodManager = inputMethodManager;
            mServedView = new WeakReference<>(servedView);
        }

        @Override
@@ -1007,6 +1000,7 @@ public final class InputMethodManager {
                    + "connection=" + getInputConnection()
                    + " finished=" + isFinished()
                    + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
                    + " mServedView=" + mServedView.get()
                    + "}";
        }
    }
@@ -1187,7 +1181,8 @@ public final class InputMethodManager {
        mMainLooper = looper;
        mH = new H(looper);
        mDisplayId = displayId;
        mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this);
        mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this,
                null);
    }

    /**
@@ -1968,7 +1963,7 @@ public final class InputMethodManager {
                    icHandler = ic.getHandler();
                }
                servedContext = new ControlledInputConnectionWrapper(
                        icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);
                        icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view);
            } else {
                servedContext = null;
                missingMethodFlags = 0;
+4 −4
Original line number Diff line number Diff line
@@ -46,10 +46,10 @@ public final class InputMethodDebug {
                return "UNSPECIFIED";
            case StartInputReason.WINDOW_FOCUS_GAIN:
                return "WINDOW_FOCUS_GAIN";
            case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR:
                return "WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR";
            case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR:
                return "WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR";
            case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION:
                return "WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION";
            case StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION:
                return "WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION";
            case StartInputReason.APP_CALLED_RESTART_INPUT_API:
                return "APP_CALLED_RESTART_INPUT_API";
            case StartInputReason.CHECK_FOCUS:
+4 −4
Original line number Diff line number Diff line
@@ -30,8 +30,8 @@ import java.lang.annotation.Retention;
@IntDef(value = {
        StartInputReason.UNSPECIFIED,
        StartInputReason.WINDOW_FOCUS_GAIN,
        StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR,
        StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR,
        StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION,
        StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION,
        StartInputReason.APP_CALLED_RESTART_INPUT_API,
        StartInputReason.CHECK_FOCUS,
        StartInputReason.BOUND_TO_IMMS,
@@ -54,13 +54,13 @@ public @interface StartInputReason {
     * view and its input connection remains. {@link android.view.inputmethod.InputMethodManager}
     * just reports this window focus change event to sync IME input target for system.
     */
    int WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR = 2;
    int WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION = 2;
    /**
     * {@link android.view.Window} gained focus but there is no {@link android.view.View} that is
     * eligible to have IME focus. {@link android.view.inputmethod.InputMethodManager} just reports
     * this window focus change event for logging.
     */
    int WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR = 3;
    int WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION = 3;
    /**
     * {@link android.view.inputmethod.InputMethodManager#restartInput(android.view.View)} is
     * either explicitly called by the application or indirectly called by some Framework class