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

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

Remove IMMS#mShowRequested

Now we have ImeTargetWindow#isRequestedImeVisible as per-window state,

To avoid this global visible state may cause some system controlled IME
visiblity issues, replace mShowRequested with
IMMS#isShowRequestedForCurrentWindow() to get the requested IME visible
state from the current focused window.

Also, in case in IMMS side may not be able to restore the IME visibility
when the activity got relaunched, updates AR#mLastImeShown state when
relaunching the activity without preserving window, and modifies
shouldRestoreImeVisiblity(windowToken) for IMMS to restore the last IME
visiblity state for that relaunching activity window.

Bug: 246309664
Test: atest InputMethodVisibilityControlTest
Test: atest CtsInputMethodDeviceTests
Change-Id: I9e69043d4aeaa2931ea192692007c7ca6420a107
parent cc573687
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ message InputMethodManagerServiceProto {
    optional string cur_focused_window_soft_input_mode = 6;
    optional .android.view.inputmethod.EditorInfoProto cur_attribute = 7;
    optional string cur_id = 8;
    optional bool show_requested = 9;
    reserved 9; // deprecated show_requested
    optional bool show_explicitly_requested = 10;
    optional bool show_forced = 11;
    optional bool input_shown = 12;
+38 −6
Original line number Diff line number Diff line
@@ -254,9 +254,16 @@ public final class ImeVisibilityStateComputer {
     *                            {@link #STATE_HIDE_IME}.
     */
    void requestImeVisibility(IBinder windowToken, boolean showIme) {
        final ImeTargetWindowState state = getOrCreateWindowState(windowToken);
        ImeTargetWindowState state = getOrCreateWindowState(windowToken);
        if (!mPolicy.mPendingA11yRequestingHideKeyboard) {
            state.setRequestedImeVisible(showIme);
        setWindowState(windowToken, state);
        } else {
            // As A11y requests no IME is just a temporary, so we don't change the requested IME
            // visible in case the last visibility state goes wrong after leaving from the a11y
            // policy.
            mPolicy.mPendingA11yRequestingHideKeyboard = false;
        }
        setWindowStateInner(windowToken, state);
    }

    ImeTargetWindowState getOrCreateWindowState(IBinder windowToken) {
@@ -276,12 +283,22 @@ public final class ImeVisibilityStateComputer {
        ImeTargetWindowState state = getWindowStateOrNull(windowToken);
        if (state != null) {
            state.setRequestImeToken(token);
            setWindowState(windowToken, state);
            setWindowStateInner(windowToken, state);
        }
    }

    void setWindowState(IBinder windowToken, @NonNull ImeTargetWindowState newState) {
        final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
        if (state != null && newState.hasEdiorFocused()) {
            // Inherit the last requested IME visible state when the target window is still
            // focused with an editor.
            newState.setRequestedImeVisible(state.mRequestedImeVisible);
        }
        setWindowStateInner(windowToken, newState);
    }

    void setWindowState(IBinder windowToken, ImeTargetWindowState newState) {
        if (DEBUG) Slog.d(TAG, "setWindowState, windowToken=" + windowToken
    private void setWindowStateInner(IBinder windowToken, @NonNull ImeTargetWindowState newState) {
        if (DEBUG) Slog.d(TAG, "setWindowStateInner, windowToken=" + windowToken
                + ", state=" + newState);
        mRequestWindowStateMap.put(windowToken, newState);
    }
@@ -330,6 +347,10 @@ public final class ImeVisibilityStateComputer {
        // UI for input.
        if (state.hasEdiorFocused() && shouldRestoreImeVisibility(state)) {
            if (DEBUG) Slog.v(TAG, "Will show input to restore visibility");
            // Inherit the last requested IME visible state when the target window is still
            // focused with an editor.
            state.setRequestedImeVisible(true);
            setWindowStateInner(getWindowTokenFrom(state), state);
            return new ImeVisibilityResult(STATE_SHOW_IME_IMPLICIT,
                    SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY);
        }
@@ -512,6 +533,14 @@ public final class ImeVisibilityStateComputer {
         */
        private boolean mA11yRequestingNoSoftKeyboard;

        /**
         * Used when A11y request to hide IME temporary when receiving
         * {@link AccessibilityService#SHOW_MODE_HIDDEN} from
         * {@link android.provider.Settings.Secure#ACCESSIBILITY_SOFT_KEYBOARD_MODE} without
         * changing the requested IME visible state.
         */
        private boolean mPendingA11yRequestingHideKeyboard;

        void setImeHiddenByDisplayPolicy(boolean hideIme) {
            mImeHiddenByDisplayPolicy = hideIme;
        }
@@ -523,6 +552,9 @@ public final class ImeVisibilityStateComputer {
        void setA11yRequestNoSoftKeyboard(int keyboardShowMode) {
            mA11yRequestingNoSoftKeyboard =
                    (keyboardShowMode & AccessibilityService.SHOW_MODE_MASK) == SHOW_MODE_HIDDEN;
            if (mA11yRequestingNoSoftKeyboard) {
                mPendingA11yRequestingHideKeyboard = true;
            }
        }

        boolean isA11yRequestNoSoftKeyboard() {
+1 −1
Original line number Diff line number Diff line
@@ -350,7 +350,7 @@ final class InputMethodBindingController {
                    // should now try to restart the service for us.
                    mLastBindTime = SystemClock.uptimeMillis();
                    clearCurMethodAndSessions();
                    mService.clearInputShowRequestLocked();
                    mService.clearInputShownLocked();
                    mService.unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
                }
            }
+14 −22
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ import static android.server.inputmethod.InputMethodManagerServiceProto.IS_INTER
import static android.server.inputmethod.InputMethodManagerServiceProto.LAST_IME_TARGET_WINDOW_NAME;
import static android.server.inputmethod.InputMethodManagerServiceProto.LAST_SWITCH_USER_ID;
import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_IME_WITH_HARD_KEYBOARD;
import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_REQUESTED;
import static android.server.inputmethod.InputMethodManagerServiceProto.SYSTEM_READY;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -623,11 +622,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        return mBindingController.hasConnection();
    }

    /**
     * Set if the client has asked for the input method to be shown.
     */
    private boolean mShowRequested;

    /** The token tracking the current IME request or {@code null} otherwise. */
    @Nullable
    private ImeTracker.Token mCurStatsToken;
@@ -1168,12 +1162,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
                    mVisibilityStateComputer.getImePolicy().setA11yRequestNoSoftKeyboard(
                            accessibilitySoftKeyboardSetting);
                    if (mVisibilityStateComputer.getImePolicy().isA11yRequestNoSoftKeyboard()) {
                        final boolean showRequested = mShowRequested;
                        hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */,
                                0 /* flags */, null /* resultReceiver */,
                                SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE);
                        mShowRequested = showRequested;
                    } else if (mShowRequested) {
                    } else if (isShowRequestedForCurrentWindow()) {
                        showCurrentInputImplicitLocked(mCurFocusedWindow,
                                SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE);
                    }
@@ -2293,8 +2285,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
    }

    @GuardedBy("ImfLock.class")
    void clearInputShowRequestLocked() {
        mShowRequested = mVisibilityStateComputer.isInputShown();
    void clearInputShownLocked() {
        mVisibilityStateComputer.setInputShown(false);
    }

@@ -2303,6 +2294,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        return mVisibilityStateComputer.isInputShown();
    }

    @GuardedBy("ImfLock.class")
    private boolean isShowRequestedForCurrentWindow() {
        final ImeTargetWindowState state = mVisibilityStateComputer.getWindowStateOrNull(
                mCurFocusedWindow);
        return state != null && state.isRequestedImeVisible();
    }

    @GuardedBy("ImfLock.class")
    @NonNull
    InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
@@ -2339,7 +2337,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        setEnabledSessionLocked(session);
        session.mMethod.startInput(startInputToken, mCurInputConnection, mCurEditorInfo, restarting,
                navButtonFlags, mCurImeDispatcher);
        if (mShowRequested) {
        if (isShowRequestedForCurrentWindow()) {
            if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
            // Re-use current statsToken, if it exists.
            final ImeTracker.Token statsToken = mCurStatsToken;
@@ -2558,7 +2556,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        if (!mPreventImeStartupUnlessTextEditor) {
            return false;
        }
        if (mShowRequested) {
        if (isShowRequestedForCurrentWindow()) {
            return false;
        }
        if (isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, startInputFlags)) {
@@ -3369,9 +3367,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
                    ImeTracker.ORIGIN_SERVER_START_INPUT, reason);
        }

        // TODO(b/246309664): make mShowRequested as per-window state.
        mShowRequested = true;

        if (!mVisibilityStateComputer.onImeShowFlags(statsToken, flags)) {
            return false;
        }
@@ -3466,7 +3461,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        // application process as a valid request, and have even promised such a behavior with CTS
        // since Android Eclair.  That's why we need to accept IMM#hideSoftInput() even when only
        // IMMS#InputShown indicates that the software keyboard is shown.
        // TODO(b/246309664): Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
        // TODO(b/246309664): Clean up IMMS#mImeWindowVis
        IInputMethodInvoker curMethod = getCurMethodLocked();
        final boolean shouldHideSoftInput = curMethod != null
                && (isInputShown() || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
@@ -3484,7 +3479,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        }
        mBindingController.setCurrentMethodNotVisible();
        mVisibilityStateComputer.clearImeShowFlags();
        mShowRequested = false;
        // Cancel existing statsToken for show IME as we got a hide request.
        ImeTracker.get().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
        mCurStatsToken = null;
@@ -4502,7 +4496,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
                mCurEditorInfo.dumpDebug(proto, CUR_ATTRIBUTE);
            }
            proto.write(CUR_ID, getCurIdLocked());
            proto.write(SHOW_REQUESTED, mShowRequested);
            mVisibilityStateComputer.dumpDebug(proto, fieldId);
            proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode);
            proto.write(CUR_TOKEN, Objects.toString(getCurTokenLocked()));
@@ -4750,7 +4743,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
                synchronized (ImfLock.class) {
                    try {
                        if (mEnabledSession != null && mEnabledSession.mSession != null
                                && !mShowRequested) {
                                && !isShowRequestedForCurrentWindow()) {
                            mEnabledSession.mSession.removeImeSurface();
                        }
                    } catch (RemoteException e) {
@@ -5738,7 +5731,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
            method = getCurMethodLocked();
            p.println("  mCurMethod=" + getCurMethodLocked());
            p.println("  mEnabledSession=" + mEnabledSession);
            p.println("  mShowRequested=" + mShowRequested);
            mVisibilityStateComputer.dump(pw);
            p.println("  mInFullscreenMode=" + mInFullscreenMode);
            p.println("  mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
+9 −0
Original line number Diff line number Diff line
@@ -9360,6 +9360,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            configChangeFlags = 0;
            return;
        }
        if (!preserveWindow) {
            // If the activity is the IME input target, ensure storing the last IME shown state
            // before relaunching it for restoring the IME visibility once its new window focused.
            final InputTarget imeInputTarget = mDisplayContent.getImeInputTarget();
            mLastImeShown = imeInputTarget != null && imeInputTarget.getWindowState() != null
                    && imeInputTarget.getWindowState().mActivityRecord == this
                    && mDisplayContent.mInputMethodWindow != null
                    && mDisplayContent.mInputMethodWindow.isVisible();
        }
        // Do not waiting for translucent activity if it is going to relaunch.
        final Task rootTask = getRootTask();
        if (rootTask != null && rootTask.mTranslucentActivityWaiting == this) {
Loading