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

Commit a981617a authored by Cosmin Băieș's avatar Cosmin Băieș
Browse files

Clear IMM#mCurRootView when needed

This clears the mCurRootView property from InputMethodManager
when it becomes inactive or loses window focus.

Before, when going from an app that had the IME shown straight
to the launcher home screen, and tapping on the Google search bar,
this would attempt to show the IME but would sometimes fail. This
is because the show flow would progress further than normal, due to
the leftover mCurRootView value in the launcher process.

Clearing this value ensures the erronous flow is cancelled early, and
due to a subsequent retry, can always succeed in showing the IME.

Test: atest android.view.inputmethod.cts.FocusHandlingTest#testClearCurRootViewWhenDifferentProcessBecomesActive
Bug: 276742733
Change-Id: Id08dece0a6b7531da6d6f8c456cd2e1d6489a9be
parent 9c6a31ea
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -3783,6 +3783,7 @@ package android.view.inputmethod {
    method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int);
    method public boolean hasActiveInputConnection(@Nullable android.view.View);
    method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean hasPendingImeVisibilityRequests();
    method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isCurrentRootView(@NonNull android.view.View);
    method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShown();
    method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void setStylusWindowIdleTimeoutForTest(long);
    field public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // 0xcc1a029L
+6 −2
Original line number Diff line number Diff line
@@ -86,10 +86,13 @@ public final class ImeFocusController {
    void onPreWindowFocus(boolean hasWindowFocus, WindowManager.LayoutParams windowAttribute) {
        mHasImeFocus = WindowManager.LayoutParams.mayUseInputMethod(windowAttribute.flags);
        if (!hasWindowFocus || !mHasImeFocus || isInLocalFocusMode(windowAttribute)) {
            return;
            if (!hasWindowFocus) {
                getImmDelegate().onWindowLostFocus(mViewRootImpl);
            }
        } else {
            getImmDelegate().onPreWindowGainedFocus(mViewRootImpl);
        }
    }

    @UiThread
    void onPostWindowFocus(View focusedView, boolean hasWindowFocus,
@@ -163,6 +166,7 @@ public final class ImeFocusController {
        void onPreWindowGainedFocus(ViewRootImpl viewRootImpl);
        void onPostWindowGainedFocus(View viewForWindowFocus,
                @NonNull WindowManager.LayoutParams windowAttribute);
        void onWindowLostFocus(@NonNull ViewRootImpl viewRootImpl);
        void onViewFocusChanged(@NonNull View view, boolean hasFocus);
        void onScheduledCheckFocus(@NonNull ViewRootImpl viewRootImpl);
        void onViewDetachedFromWindow(View view, ViewRootImpl viewRootImpl);
+60 −5
Original line number Diff line number Diff line
@@ -482,12 +482,20 @@ public final class InputMethodManager {
    private View mNextServedView;

    /**
     * This is the root view of the overall window that currently has input
     * method focus.
     * The latest {@link ViewRootImpl} that has, or most recently had, input method focus.
     *
     * <p>This value will be cleared when it becomes inactive and no longer has window focus.
     */
    @Nullable
    @GuardedBy("mH")
    ViewRootImpl mCurRootView;

    /**
     * Whether the {@link #mCurRootView} currently has window focus.
     */
    @GuardedBy("mH")
    boolean mCurRootViewWindowFocused;

    /**
     * This is set when we are in the process of connecting, to determine
     * when we have actually finished.
@@ -745,6 +753,7 @@ public final class InputMethodManager {
        public void onPreWindowGainedFocus(ViewRootImpl viewRootImpl) {
            synchronized (mH) {
                setCurrentRootViewLocked(viewRootImpl);
                mCurRootViewWindowFocused = true;
            }
        }

@@ -821,6 +830,17 @@ public final class InputMethodManager {
            }
        }

        @Override
        public void onWindowLostFocus(@NonNull ViewRootImpl viewRootImpl) {
            synchronized (mH) {
                if (mCurRootView == viewRootImpl) {
                    mCurRootViewWindowFocused = false;

                    clearCurRootViewIfNeeded();
                }
            }
        }

        @Override
        public void onViewFocusChanged(@Nullable View view, boolean hasFocus) {
            onViewFocusChangedInternal(view, hasFocus);
@@ -1114,6 +1134,10 @@ public final class InputMethodManager {
                            // Note that finishComposingText() is allowed to run
                            // even when we are not active.
                            mFallbackInputConnection.finishComposingTextFromImm();

                            if (clearCurRootViewIfNeeded()) {
                                return;
                            }
                        }
                        // Check focus again in case that "onWindowFocus" is called before
                        // handling this message.
@@ -1756,8 +1780,7 @@ public final class InputMethodManager {
    }

    /**
     * Return true if the given view is the currently active view for the
     * input method.
     * Return {@code true} if the given view is the currently active view for the input method.
     */
    public boolean isActive(View view) {
        // Re-dispatch if there is a context mismatch.
@@ -1773,7 +1796,7 @@ public final class InputMethodManager {
    }

    /**
     * Return true if any view is currently active in the input method.
     * Return {@code true} if any view is currently active for the input method.
     */
    public boolean isActive() {
        checkFocus();
@@ -1782,6 +1805,20 @@ public final class InputMethodManager {
        }
    }

    /**
     * Returns {@code true} if the given view's {@link ViewRootImpl} is the currently active one
     * for the {@code InputMethodManager}.
     *
     * @hide
     */
    @TestApi
    @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
    public boolean isCurrentRootView(@NonNull View attachedView) {
        synchronized (mH) {
            return mCurRootView == attachedView.getViewRootImpl();
        }
    }

    /**
     * Return {@code true} if the currently served view is accepting full text edits.
     * If {@code false}, it has no input connection, so it can only handle raw key events.
@@ -1908,6 +1945,24 @@ public final class InputMethodManager {
        mImeDispatcher.clear();
    }

    /**
     * Clears the {@link #mCurRootView} if it's no longer window focused and the connection is
     * no longer active.
     *
     * @return {@code} true iff it was cleared.
     */
    @GuardedBy("mH")
    private boolean clearCurRootViewIfNeeded() {
        if (!mActive && !mCurRootViewWindowFocused) {
            finishInputLocked();
            mDelegate.setCurrentRootViewLocked(null);

            return true;
        }

        return false;
    }

    public void displayCompletions(View view, CompletionInfo[] completions) {
        // Re-dispatch if there is a context mismatch.
        final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);