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

Commit e3488605 authored by Ming-Shin Lu's avatar Ming-Shin Lu
Browse files

Fix showing keyboard without editor focused in some cases (1/2)

Starts from CL[1] that reporting focus change is now driven by
input instead window manager, so the window focus sequence for the
activity with EditTextPreference dialog after device unlock
in between android Q and android R will be:

[Android Q]:
activity main window (with softInputMode STATE_UNSPECIFIED)
    -> EditTextPreference (with softInputMode STATE_ALWAYS_VISIBLE)

[Android R]:
Only EditTextPreference focused after device unlocked since the window
is the last touched window.

Since in Q, the softInputMode of activity main window is STATE_UNSPECIFIED
, so by default InputMethodManagerService will hide soft-keyboard if there
is no editor focused according this softInputMode flag.

However, in R, because no main window focused, so after EditTextPerference
focused and started the input connection, this will hit a logic to show
soft-keyboard, if mShowRequested is true after the input session created.

Since IMMS#mShowRequested originally is used to show soft-input while
showSoftInput is called but IME service has been unbounded (e.g. switch IME
or IME service killed), so use this flag can show soft-input aftter
service re-connected.  For the issue case, we should ignore
STATE_ALWAYS_VISIBLE since the app's targetSdkVersion is P+ and no
editor focus as CL[2] expectation.

To fix that, we introduced new SoftInputShowHideReason to hide
soft-input when the same window focused without valid editor focus
after screen unlock, in order to align with the behavior prior to R.

[1]: Iff0b88a05441b29834741aa3dfae31d55871ddd6
[2]: I56682c7dee71d461687b9e80ab746d382fd55e0c

Bug: 161506356
Fix: 162444230
Test: atest CtsInputMethodTestCases
Merged-In: I37ae6e30d1de581ba15131c2a90396b3a522a4d6
Change-Id: I37ae6e30d1de581ba15131c2a90396b3a522a4d6
(cherry picked from commit 1ef07dff)
parent 74237cc1
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -224,6 +224,8 @@ public final class InputMethodDebug {
                return "HIDE_DOCKED_STACK_ATTACHED";
            case SoftInputShowHideReason.HIDE_RECENTS_ANIMATION:
                return "HIDE_RECENTS_ANIMATION";
            case SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR:
                return "HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR";
            default:
                return "Unknown=" + reason;
        }
+15 −1
Original line number Diff line number Diff line
@@ -47,7 +47,8 @@ import java.lang.annotation.Retention;
        SoftInputShowHideReason.HIDE_POWER_BUTTON_GO_HOME,
        SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED,
        SoftInputShowHideReason.HIDE_RECENTS_ANIMATION,
        SoftInputShowHideReason.HIDE_BUBBLES})
        SoftInputShowHideReason.HIDE_BUBBLES,
        SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR})
public @interface SoftInputShowHideReason {
    /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
    int SHOW_SOFT_INPUT = 0;
@@ -147,4 +148,17 @@ public @interface SoftInputShowHideReason {
     * switching, or collapsing Bubbles.
     */
    int HIDE_BUBBLES = 19;

    /**
     * Hide soft input when focusing the same window (e.g. screen turned-off and turn-on) which no
     * valid focused editor.
     *
     * Note: From Android R, the window focus change callback is processed by InputDispatcher,
     * some focus behavior changes (e.g. There are an activity with a dialog window, after
     * screen turned-off and turned-on, before Android R the window focus sequence would be
     * the activity first and then the dialog focused, however, in R the focus sequence would be
     * only the dialog focused as it's the latest window with input focus) makes we need to hide
     * soft-input when the same window focused again to align with the same behavior prior to R.
     */
    int HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR = 20;
}
+32 −12
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ import android.inputmethodservice.InputMethodService;
import android.media.AudioManagerInternal;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
@@ -3273,6 +3274,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub

    boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
            @SoftInputShowHideReason int reason) {
        if (mCurClient == null || mCurClient.curSession == null) {
            return false;
        }
        if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
                && (mShowExplicitlyRequested || mShowForced)) {
            if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
@@ -3457,7 +3461,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        // pre-rendering not supported on low-ram devices.
        cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;

        if (mCurFocusedWindow == windowToken) {
        final boolean sameWindowFocused = mCurFocusedWindow == windowToken;
        final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
        if (sameWindowFocused && isTextEditor) {
            if (DEBUG) {
                Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
                        + " attribute=" + attribute + ", token = " + windowToken
@@ -3472,6 +3478,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                    InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
                    null, null, null, -1, null);
        }

        mCurFocusedWindow = windowToken;
        mCurFocusedWindowSoftInputMode = softInputMode;
        mCurFocusedWindowClient = cs;
@@ -3489,7 +3496,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                        == LayoutParams.SOFT_INPUT_ADJUST_RESIZE
                || mRes.getConfiguration().isLayoutSizeAtLeast(
                        Configuration.SCREENLAYOUT_SIZE_LARGE);
        final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;

        // We want to start input before showing the IME, but after closing
        // it.  We want to do this after closing it to help the IME disappear
@@ -3549,9 +3555,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                }
                break;
            case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
                if (!sameWindowFocused) {
                    if (DEBUG) Slog.v(TAG, "Window asks to hide input");
                    hideCurrentInputLocked(mCurFocusedWindow, 0, null,
                            SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE);
                }
                break;
            case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
                if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
@@ -3576,6 +3584,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                if (DEBUG) Slog.v(TAG, "Window asks to always show input");
                if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
                        unverifiedTargetSdkVersion, startInputFlags)) {
                    if (!sameWindowFocused) {
                        if (attribute != null) {
                            res = startInputUncheckedLocked(cs, inputContext, missingMethods,
                                    attribute, startInputFlags, startInputReason);
@@ -3583,6 +3592,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                        }
                        showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
                                SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE);
                    }
                } else {
                    Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
                            + " there is no focused view that also returns true from"
@@ -3593,7 +3603,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub

        if (!didStart) {
            if (attribute != null) {
                if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
                if (sameWindowFocused) {
                    hideCurrentInputLocked(mCurFocusedWindow, 0, null,
                            SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
                    res = new InputBindResult(
                            InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
                            null, null, null, -1, null);
                } else if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
                        || (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) {
                    res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
                            startInputFlags, startInputReason);
@@ -3607,6 +3623,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        return res;
    }

    private boolean isImeVisible() {
        return (mImeWindowVis & InputMethodService.IME_VISIBLE) != 0;
    }

    private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
        // TODO(yukawa): multi-display support.
        final int uid = Binder.getCallingUid();