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

Commit d3ede6ef authored by Felix Stern's avatar Felix Stern
Browse files

Remove VisibilityState flags and simplify DefaultImeVisibilityApplier

Previously (before [1]), those flags were used as an indicator whether
the IME should been shown or hidden, As we're not depending on
additional attributes anymore, we can simplify the cases and just call
show/hide directly.

[1]: I8e3a74ee579f085cb582040fdba725e7a63d6b85

Fixes: 433457669
Test: atest DefaultImeVisibilityApplierTest ImeVisibilityStateComputerTest
Flag: EXEMPT refactor
Change-Id: I1399ec6c9e3f5ed70f02ba2326edd0c73eb930b4
parent 77d7df1c
Loading
Loading
Loading
Loading
+0 −41
Original line number Diff line number Diff line
@@ -21,11 +21,6 @@ import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;
import static com.android.server.EventLogTags.IMF_HIDE_IME;
import static com.android.server.EventLogTags.IMF_SHOW_IME;
import static com.android.server.inputmethod.ImeProtoLogGroup.IME_VISIBILITY_APPLIER_DEBUG;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_NOT_ALWAYS;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_IMPLICIT;

import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -40,7 +35,6 @@ import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.protolog.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.wm.ImeTargetVisibilityPolicy;
import com.android.server.wm.WindowManagerInternal;

import java.util.Objects;

@@ -54,14 +48,11 @@ final class DefaultImeVisibilityApplier {

    private InputMethodManagerService mService;

    private final WindowManagerInternal mWindowManagerInternal;

    @NonNull
    private final ImeTargetVisibilityPolicy mImeTargetVisibilityPolicy;

    DefaultImeVisibilityApplier(InputMethodManagerService service) {
        mService = service;
        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
        mImeTargetVisibilityPolicy = LocalServices.getService(ImeTargetVisibilityPolicy.class);
    }

@@ -139,38 +130,6 @@ final class DefaultImeVisibilityApplier {
        }
    }

    /**
     * Applies the IME visibility from {@link android.inputmethodservice.InputMethodService} with
     * according to the given visibility state.
     *
     * @param statsToken the token tracking the current IME request
     * @param state      the new IME visibility state for the applier to handle
     * @param userId     the target user when applying the IME visibility state
     */
    @GuardedBy("ImfLock.class")
    void applyImeVisibility(@NonNull ImeTracker.Token statsToken,
            @ImeVisibilityStateComputer.VisibilityState int state,
            @UserIdInt int userId) {
        final var userData = mService.getUserData(userId);
        switch (state) {
            case STATE_SHOW_IME:
            case STATE_HIDE_IME:
                // no-op
                break;
            case STATE_HIDE_IME_EXPLICIT:
            case STATE_HIDE_IME_NOT_ALWAYS:
                mService.setImeVisibilityOnFocusedWindowClient(false, userData, statsToken);
                break;
            case STATE_SHOW_IME_IMPLICIT:
                // This can be triggered by IMMS#startInputOrWindowGainedFocus. We need to
                // set the requestedVisibleTypes in InsetsController first, before applying it.
                mService.setImeVisibilityOnFocusedWindowClient(true, userData, statsToken);
                break;
            default:
                throw new IllegalArgumentException("Invalid IME visibility state: " + state);
        }
    }

    /**
     * Applies the IME screenshot visibility on the given IME target window.
     *
+15 −51
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@ import static com.android.server.inputmethod.InputMethodManagerService.computeIm

import android.accessibilityservice.AccessibilityService;
import android.annotation.AnyThread;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -117,39 +116,6 @@ public final class ImeVisibilityStateComputer {
    @Nullable
    private IBinder mLastImeTargetWindow;

    /** Represent the invalid IME visibility state */
    public static final int STATE_INVALID = -1;

    /** State to handle hiding the IME window requested by the app. */
    public static final int STATE_HIDE_IME = 0;

    /** State to handle showing the IME window requested by the app. */
    public static final int STATE_SHOW_IME = 1;

    /** State to handle showing the IME window with making the overlay window above it.  */
    public static final int STATE_SHOW_IME_ABOVE_OVERLAY = 2;

    /** State to handle showing the IME window with making the overlay window behind it.  */
    public static final int STATE_SHOW_IME_BEHIND_OVERLAY = 3;

    public static final int STATE_HIDE_IME_EXPLICIT = 4;

    public static final int STATE_HIDE_IME_NOT_ALWAYS = 5;

    public static final int STATE_SHOW_IME_IMPLICIT = 6;

    @IntDef({
            STATE_INVALID,
            STATE_HIDE_IME,
            STATE_SHOW_IME,
            STATE_SHOW_IME_ABOVE_OVERLAY,
            STATE_SHOW_IME_BEHIND_OVERLAY,
            STATE_HIDE_IME_EXPLICIT,
            STATE_HIDE_IME_NOT_ALWAYS,
            STATE_SHOW_IME_IMPLICIT,
    })
    @interface VisibilityState {}

    /**
     * The policy to configure the IME visibility.
     */
@@ -215,8 +181,9 @@ public final class ImeVisibilityStateComputer {
            final int reason = SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE;
            final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
                    ImeTracker.ORIGIN_SERVER, reason, false /* fromUser */);
            mService.onApplyImeVisibilityFromComputerLocked(statsToken,
                    new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT, reason), mUserId);
            final var userData = mService.getUserData(mUserId);
            mService.setImeVisibilityOnFocusedWindowClient(false /* visible */, userData,
                    statsToken);
        }
        mCurVisibleImeInputTarget = null;
    }
@@ -254,9 +221,6 @@ public final class ImeVisibilityStateComputer {
     *
     * @param windowToken The window which requests to show/hide IME.
     * @param showIme {@code true} means to show IME, {@code false} otherwise.
     *                            Note that in the computer will take this option to compute the
     *                            visibility state, it could be {@link #STATE_SHOW_IME} or
     *                            {@link #STATE_HIDE_IME}.
     */
    @GuardedBy("ImfLock.class")
    void requestImeVisibility(IBinder windowToken, boolean showIme) {
@@ -310,16 +274,16 @@ public final class ImeVisibilityStateComputer {
    }

    static class ImeVisibilityResult {
        private final @VisibilityState int mState;
        private final boolean mVisible;
        private final @SoftInputShowHideReason int mReason;

        ImeVisibilityResult(@VisibilityState int state, @SoftInputShowHideReason int reason) {
            mState = state;
        ImeVisibilityResult(boolean visible, @SoftInputShowHideReason int reason) {
            mVisible = visible;
            mReason = reason;
        }

        @VisibilityState int getState() {
            return mState;
        public boolean isVisible() {
            return mVisible;
        }

        @SoftInputShowHideReason int getReason() {
@@ -373,7 +337,7 @@ public final class ImeVisibilityStateComputer {
            // focused with an editor.
            state.setRequestedImeVisible(true);
            setWindowStateInner(getWindowTokenFrom(state), state);
            return new ImeVisibilityResult(STATE_SHOW_IME_IMPLICIT,
            return new ImeVisibilityResult(true /* visible */,
                    SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY);
        }

@@ -386,7 +350,7 @@ public final class ImeVisibilityStateComputer {
                        // soft input window if it is shown.
                        ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG,
                                "Unspecified window will hide input");
                        return new ImeVisibilityResult(STATE_HIDE_IME_NOT_ALWAYS,
                        return new ImeVisibilityResult(false /* visible */,
                                SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW);
                    }
                } else if (state.hasEditorFocused() && doAutoShow && isForwardNavigation) {
@@ -398,7 +362,7 @@ public final class ImeVisibilityStateComputer {
                    // by the IME) or if running on a large screen where there
                    // is more room for the target window + IME.
                    ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG, "Unspecified window will show input");
                    return new ImeVisibilityResult(STATE_SHOW_IME_IMPLICIT,
                    return new ImeVisibilityResult(true /* visible */,
                            SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV);
                }
                break;
@@ -422,7 +386,7 @@ public final class ImeVisibilityStateComputer {
                    if (allowVisible) {
                        ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG,
                                "Window asks to show input going forward");
                        return new ImeVisibilityResult(STATE_SHOW_IME_IMPLICIT,
                        return new ImeVisibilityResult(true /* visible */,
                                SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV);
                    } else {
                        Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because"
@@ -435,7 +399,7 @@ public final class ImeVisibilityStateComputer {
                ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG, "Window asks to always show input");
                if (allowVisible) {
                    if (state.hasImeFocusChanged()) {
                        return new ImeVisibilityResult(STATE_SHOW_IME_IMPLICIT,
                        return new ImeVisibilityResult(true /* visible */,
                                SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE);
                    }
                } else {
@@ -456,7 +420,7 @@ public final class ImeVisibilityStateComputer {
            if (state.isStartInputByWindowGainFocus()) {
                ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG,
                        "Same window without editor will hide input");
                return new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT,
                return new ImeVisibilityResult(false /* visible */,
                        SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
            }
        }
@@ -472,7 +436,7 @@ public final class ImeVisibilityStateComputer {
            // 3) SOFT_INPUT_STATE_ALWAYS_VISIBLE state without an editor
            ProtoLog.v(IME_VIS_STATE_COMPUTER_DEBUG, "Window without editor will hide input");
            state.setRequestedImeVisible(false);
            return new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT,
            return new ImeVisibilityResult(false /* visible */,
                    SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR);
        }
        return null;
+1 −7
Original line number Diff line number Diff line
@@ -3751,7 +3751,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
            }
            final var statsToken = createStatsTokenForFocusedClient(isShow, imeVisRes.getReason(),
                    userId);
            mVisibilityApplier.applyImeVisibility(statsToken, imeVisRes.getState(), userId);
            setImeVisibilityOnFocusedWindowClient(imeVisRes.isVisible(), userData, statsToken);
            if (imeVisRes.getReason() == SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW) {
                // If focused display changed, we should unbind current method
                // to make app window in previous display relayout after Ime
@@ -4585,12 +4585,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
        return mVisibilityApplier;
    }

    @GuardedBy("ImfLock.class")
    void onApplyImeVisibilityFromComputerLocked(@NonNull ImeTracker.Token statsToken,
            @NonNull ImeVisibilityResult result, @UserIdInt int userId) {
        mVisibilityApplier.applyImeVisibility(statsToken, result.getState(), userId);
    }

    @GuardedBy("ImfLock.class")
    void setEnabledSessionLocked(SessionState session, @NonNull UserData userData) {
        if (userData.mEnabledSession != session) {
+0 −54
Original line number Diff line number Diff line
@@ -16,19 +16,11 @@

package com.android.server.inputmethod;

import static android.inputmethodservice.InputMethodService.IME_ACTIVE;

import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_SOFT_INPUT;
import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_SOFT_INPUT;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_NOT_ALWAYS;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_INVALID;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_IMPLICIT;

import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import static java.util.Objects.requireNonNull;

@@ -93,52 +85,6 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe
        verifyHideSoftInput(false, true);
    }

    @Test
    public void testApplyImeVisibility_throwForInvalidState() {
        assertThrows(IllegalArgumentException.class, () -> {
            synchronized (ImfLock.class) {
                mVisibilityApplier.applyImeVisibility(ImeTracker.Token.empty(),
                        STATE_INVALID, mUserId);
            }
        });
    }

    @Test
    public void testApplyImeVisibility_hideImeExplicit() throws Exception {
        synchronized (ImfLock.class) {
            final var bindingController =
                    mInputMethodManagerService.getInputMethodBindingController(mUserId);
            when(bindingController.getImeWindowVis()).thenReturn(IME_ACTIVE);
            mVisibilityApplier.applyImeVisibility(ImeTracker.Token.empty(),
                    STATE_HIDE_IME_EXPLICIT, mUserId);
        }
        verifySetImeVisibility(true /* setVisible */, false /* invoked */);
        verifySetImeVisibility(false /* setVisible */, true /* invoked */);
    }

    @Test
    public void testApplyImeVisibility_hideNotAlways() throws Exception {
        synchronized (ImfLock.class) {
            final var bindingController =
                    mInputMethodManagerService.getInputMethodBindingController(mUserId);
            when(bindingController.getImeWindowVis()).thenReturn(IME_ACTIVE);
            mVisibilityApplier.applyImeVisibility(ImeTracker.Token.empty(),
                    STATE_HIDE_IME_NOT_ALWAYS, mUserId);
        }
        verifySetImeVisibility(true /* setVisible */, false /* invoked */);
        verifySetImeVisibility(false /* setVisible */, true /* invoked */);
    }

    @Test
    public void testApplyImeVisibility_showImeImplicit() throws Exception {
        synchronized (ImfLock.class) {
            mVisibilityApplier.applyImeVisibility(ImeTracker.Token.empty(),
                    STATE_SHOW_IME_IMPLICIT, mUserId);
        }
        verifySetImeVisibility(true /* setVisible */, true /* invoked */);
        verifySetImeVisibility(false /* setVisible */, false /* invoked */);
    }

    @Test
    public void testShowImeScreenshot() {
        synchronized (ImfLock.class) {
+7 −13
Original line number Diff line number Diff line
@@ -26,15 +26,13 @@ import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeTargetWindowState;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeVisibilityResult;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT;
import static com.android.server.inputmethod.InputMethodManagerService.FALLBACK_DISPLAY_ID;
import static com.android.server.inputmethod.InputMethodManagerService.ImeDisplayValidator;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;

import android.annotation.UserIdInt;
@@ -263,18 +261,14 @@ public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTes
            mComputer.setHasVisibleImeLayeringOverlay(true /* visibleAndNotRemoved */);
            mComputer.onImeInputTargetVisibilityChanged(testImeInputTarget,
                    false /* visibleAndNotRemoved */);
            final ArgumentCaptor<ImeVisibilityResult> resultCaptor = ArgumentCaptor.forClass(
                    ImeVisibilityResult.class);
            final ArgumentCaptor<Integer> userIdCaptor = ArgumentCaptor.forClass(Integer.class);
            verify(mInputMethodManagerService).onApplyImeVisibilityFromComputerLocked(
                    notNull() /* statsToken */, resultCaptor.capture(), userIdCaptor.capture());
            final ImeVisibilityResult result = resultCaptor.getValue();
            final int userId = userIdCaptor.getValue();
            final ArgumentCaptor<UserData> userDataCaptor = ArgumentCaptor.forClass(UserData.class);
            verify(mInputMethodManagerService).setImeVisibilityOnFocusedWindowClient(
                    eq(false) /* visible */, userDataCaptor.capture(), notNull() /* statsToken */);
            final UserData userData = userDataCaptor.getValue();

            // Verify the computer will callback hiding IME state to IMMS.
            assertThat(result.getState()).isEqualTo(STATE_HIDE_IME_EXPLICIT);
            assertThat(result.getReason()).isEqualTo(HIDE_WHEN_INPUT_TARGET_INVISIBLE);
            assertThat(userId).isEqualTo(mUserId);
            assertThat(userData).isNotNull();
            assertThat(userData.mUserId).isEqualTo(mUserId);
        }
    }