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

Commit ec45cc5b authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Make IMMS#mVisibilityStateComputer multi-user aware

This is a mechanical CL to instantiate ImeVisibilityStateComputer for
each user.

There must be no observable behavior change in the single user mode.

Fix: 349904272
Test: presubmit
Test: atest FrameworksInputMethodSystemServerTests
Flag: android.view.inputmethod.concurrent_input_methods
Change-Id: I296c8fbca87100178e30c0bb529fbcade377ec50
parent 035470ae
Loading
Loading
Loading
Loading
+44 −46
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVI
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;

import static com.android.internal.inputmethod.InputMethodDebug.softInputModeToString;
import static com.android.internal.inputmethod.SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS;
@@ -59,7 +58,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.server.LocalServices;
import com.android.server.wm.ImeTargetChangeListener;
import com.android.server.wm.WindowManagerInternal;

import java.io.PrintWriter;
@@ -76,6 +74,9 @@ public final class ImeVisibilityStateComputer {

    private static final boolean DEBUG = InputMethodManagerService.DEBUG;

    @UserIdInt
    private final int mUserId;

    private final InputMethodManagerService mService;
    private final WindowManagerInternal mWindowManagerInternal;

@@ -184,57 +185,51 @@ public final class ImeVisibilityStateComputer {
     */
    private final ImeVisibilityPolicy mPolicy;

    public ImeVisibilityStateComputer(@NonNull InputMethodManagerService service) {
    public ImeVisibilityStateComputer(@NonNull InputMethodManagerService service,
            @UserIdInt int userId) {
        this(service,
                LocalServices.getService(WindowManagerInternal.class),
                LocalServices.getService(WindowManagerInternal.class)::getDisplayImePolicy,
                new ImeVisibilityPolicy());
                new ImeVisibilityPolicy(), userId);
    }

    @VisibleForTesting
    public ImeVisibilityStateComputer(@NonNull InputMethodManagerService service,
            @NonNull Injector injector) {
        this(service, injector.getWmService(), injector.getImeValidator(),
                new ImeVisibilityPolicy());
                new ImeVisibilityPolicy(), injector.getUserId());
    }

    interface Injector {
        default WindowManagerInternal getWmService() {
            return null;
        }
        @NonNull
        WindowManagerInternal getWmService();

        default InputMethodManagerService.ImeDisplayValidator getImeValidator() {
            return null;
        }
        @NonNull
        InputMethodManagerService.ImeDisplayValidator getImeValidator();

        @UserIdInt
        int getUserId();
    }

    private ImeVisibilityStateComputer(InputMethodManagerService service,
            WindowManagerInternal wmService,
            InputMethodManagerService.ImeDisplayValidator imeDisplayValidator,
            ImeVisibilityPolicy imePolicy) {
            ImeVisibilityPolicy imePolicy, @UserIdInt int userId) {
        mUserId = userId;
        mService = service;
        mWindowManagerInternal = wmService;
        mImeDisplayValidator = imeDisplayValidator;
        mPolicy = imePolicy;
        mWindowManagerInternal.setInputMethodTargetChangeListener(new ImeTargetChangeListener() {
            @Override
            public void onImeTargetOverlayVisibilityChanged(@NonNull IBinder overlayWindowToken,
                    @WindowManager.LayoutParams.WindowType int windowType, boolean visible,
                    boolean removed, int displayId) {
                // Ignoring the starting window since it's ok to cover the IME target
                // window in temporary without affecting the IME visibility.
                final boolean hasOverlay = visible && !removed
                        && windowType != TYPE_APPLICATION_STARTING;
                synchronized (ImfLock.class) {
                    mHasVisibleImeLayeringOverlay = hasOverlay;
    }

    @GuardedBy("ImfLock.class")
    void setHasVisibleImeLayeringOverlay(boolean hasVisibleOverlay) {
        mHasVisibleImeLayeringOverlay = hasVisibleOverlay;
    }

            @Override
            public void onImeInputTargetVisibilityChanged(IBinder imeInputTarget,
                    boolean visibleRequested, boolean removed, int displayId) {
                final boolean visibleAndNotRemoved = visibleRequested && !removed;
                synchronized (ImfLock.class) {
    @GuardedBy("ImfLock.class")
    void onImeInputTargetVisibilityChanged(@NonNull IBinder imeInputTarget,
            boolean visibleAndNotRemoved) {
        if (visibleAndNotRemoved) {
            mCurVisibleImeInputTarget = imeInputTarget;
            return;
@@ -245,13 +240,10 @@ public final class ImeVisibilityStateComputer {
            final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
                    ImeTracker.ORIGIN_SERVER, reason, false /* fromUser */);
            mService.onApplyImeVisibilityFromComputerLocked(imeInputTarget, statsToken,
                                new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT, reason));
                    new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT, reason), mUserId);
        }
        mCurVisibleImeInputTarget = null;
    }
            }
        });
    }

    /**
     * Called when {@link InputMethodManagerService} is processing the show IME request.
@@ -631,6 +623,12 @@ public final class ImeVisibilityStateComputer {
        return mWindowManagerInternal.shouldRestoreImeVisibility(getWindowTokenFrom(state));
    }

    @UserIdInt
    @VisibleForTesting
    int getUserId() {
        return mUserId;
    }

    @GuardedBy("ImfLock.class")
    boolean isInputShown() {
        return mInputShown;
+2 −1
Original line number Diff line number Diff line
@@ -463,7 +463,8 @@ final class InputMethodBindingController {
                    // should now try to restart the service for us.
                    mLastBindTime = SystemClock.uptimeMillis();
                    clearCurMethodAndSessions();
                    mService.mVisibilityStateComputer.setInputShown(false);
                    final var userData = mService.getUserData(mUserId);
                    userData.mVisibilityStateComputer.setInputShown(false);
                    mService.unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME, mUserId);
                }
            }
+122 −66

File changed.

Preview size limit exceeded, changes collapsed.

+6 −1
Original line number Diff line number Diff line
@@ -66,6 +66,9 @@ final class UserData {
    final HardwareKeyboardShortcutController mHardwareKeyboardShortcutController =
            new HardwareKeyboardShortcutController();

    @NonNull
    final ImeVisibilityStateComputer mVisibilityStateComputer;

    /**
     * Have we called mCurMethod.bindInput()?
     */
@@ -155,9 +158,11 @@ final class UserData {
     * Intended to be instantiated only from this file.
     */
    UserData(@UserIdInt int userId,
            @NonNull InputMethodBindingController bindingController) {
            @NonNull InputMethodBindingController bindingController,
            @NonNull ImeVisibilityStateComputer stateComputer) {
        mUserId = userId;
        mBindingController = bindingController;
        mVisibilityStateComputer = stateComputer;
    }

    @Override
+8 −3
Original line number Diff line number Diff line
@@ -30,7 +30,10 @@ final class UserDataRepository {
    @NonNull
    private volatile ImmutableSparseArray<UserData> mUserData = ImmutableSparseArray.empty();

    @NonNull
    private final IntFunction<InputMethodBindingController> mBindingControllerFactory;
    @NonNull
    private final IntFunction<ImeVisibilityStateComputer> mVisibilityStateComputerFactory;

    @AnyThread
    @NonNull
@@ -42,7 +45,8 @@ final class UserDataRepository {
        }
        // Note that the below line can be called concurrently. Here we assume that
        // instantiating UserData for the same user multiple times would have no side effect.
        final var newUserData = new UserData(userId, mBindingControllerFactory.apply(userId));
        final var newUserData = new UserData(userId, mBindingControllerFactory.apply(userId),
                mVisibilityStateComputerFactory.apply(userId));
        synchronized (mMutationLock) {
            mUserData = mUserData.cloneWithPutOrSelf(userId, newUserData);
            return newUserData;
@@ -54,9 +58,10 @@ final class UserDataRepository {
        mUserData.forEach(consumer);
    }

    UserDataRepository(
            @NonNull IntFunction<InputMethodBindingController> bindingControllerFactory) {
    UserDataRepository(@NonNull IntFunction<InputMethodBindingController> bindingControllerFactory,
            @NonNull IntFunction<ImeVisibilityStateComputer> visibilityStateComputerFactory) {
        mBindingControllerFactory = bindingControllerFactory;
        mVisibilityStateComputerFactory = visibilityStateComputerFactory;
    }

    @AnyThread
Loading