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

Commit d2b417f9 authored by Antonio Kantek's avatar Antonio Kantek
Browse files

Move InputBindingController to UserData

This is a preparation CL for changing IMMS to store
InputBindingController per user.

This is a refactoring CL, no regression is expected.

Bug: 325515685
Test: atest CtsInputMethodTestCases FrameworksServicesTests
Change-Id: I870a76ac1d196436f1b2f172d65ac46d580650d6
parent 1836f6d4
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -118,6 +118,14 @@ final class InputMethodBindingController {
        mLatchForTesting = latchForTesting;
    }

    /**
     * Interface used to abstract {@code InputMethodBindingController} instantiation.
     */
    interface Creator {

        InputMethodBindingController create();
    }

    /**
     * Time that we last initiated a bind to the input method, to determine
     * if we should try to disconnect and reconnect to it.
+60 −39
Original line number Diff line number Diff line
@@ -303,8 +303,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
    @MultiUserUnawareField
    private final InputMethodMenuController mMenuController;
    @MultiUserUnawareField
    @NonNull private final InputMethodBindingController mBindingController;
    @MultiUserUnawareField
    @NonNull private final AutofillSuggestionsController mAutofillController;

    @GuardedBy("ImfLock.class")
@@ -465,12 +463,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
    @GuardedBy("ImfLock.class")
    @Nullable
    String getSelectedMethodIdLocked() {
        return mBindingController.getSelectedMethodId();
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        return userData.mBindingController.getSelectedMethodId();
    }

    @GuardedBy("ImfLock.class")
    private void setSelectedMethodIdLocked(@Nullable String selectedMethodId) {
        mBindingController.setSelectedMethodId(selectedMethodId);
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        userData.mBindingController.setSelectedMethodId(selectedMethodId);
    }

    /**
@@ -479,8 +479,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
     */
    @GuardedBy("ImfLock.class")
    private int getSequenceNumberLocked() {
        final UserData monitor = UserData.getOrCreate(mCurrentUserId);
        return monitor.mSequence.getSequenceNumber();
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        return userData.mSequence.getSequenceNumber();
    }

    /**
@@ -550,7 +550,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
    @GuardedBy("ImfLock.class")
    @Nullable
    private String getCurIdLocked() {
        return mBindingController.getCurId();
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        return userData.mBindingController.getCurId();
    }

    /**
@@ -574,7 +575,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
     */
    @GuardedBy("ImfLock.class")
    private boolean hasConnectionLocked() {
        return mBindingController.hasMainConnection();
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        return userData.mBindingController.hasMainConnection();
    }

    /**
@@ -597,7 +599,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
    @GuardedBy("ImfLock.class")
    @Nullable
    private Intent getCurIntentLocked() {
        return mBindingController.getCurIntent();
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        return userData.mBindingController.getCurIntent();
    }

    /**
@@ -607,7 +610,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
    @GuardedBy("ImfLock.class")
    @Nullable
    IBinder getCurTokenLocked() {
        return mBindingController.getCurToken();
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        return userData.mBindingController.getCurToken();
    }

    /**
@@ -648,7 +652,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
    @GuardedBy("ImfLock.class")
    @Nullable
    IInputMethodInvoker getCurMethodLocked() {
        return mBindingController.getCurMethod();
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        return userData.mBindingController.getCurMethod();
    }

    /**
@@ -656,7 +661,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
     */
    @GuardedBy("ImfLock.class")
    private int getCurMethodUidLocked() {
        return mBindingController.getCurMethodUid();
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        return userData.mBindingController.getCurMethodUid();
    }

    /**
@@ -665,7 +671,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
     */
    @GuardedBy("ImfLock.class")
    private long getLastBindTimeLocked() {
        return mBindingController.getLastBindTime();
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        return userData.mBindingController.getLastBindTime();
    }

    /**
@@ -1371,7 +1378,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        // InputMethodSettingsRepository should be initialized before buildInputMethodListLocked
        InputMethodSettingsRepository.initialize(mHandler, mContext);
        AdditionalSubtypeMapRepository.initialize(mHandler, mContext);
        UserData.initialize(mHandler);

        mCurrentUserId = mActivityManagerInternal.getCurrentUserId();

@@ -1384,19 +1390,17 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
                new HardwareKeyboardShortcutController(settings.getMethodMap(),
                        settings.getUserId());
        mMenuController = new InputMethodMenuController(this);
        mBindingController =
                bindingControllerForTesting != null
                        ? bindingControllerForTesting
                        : new InputMethodBindingController(this);
        mAutofillController = new AutofillSuggestionsController(this);

        mVisibilityStateComputer = new ImeVisibilityStateComputer(this);
        mVisibilityApplier = new DefaultImeVisibilityApplier(this);

        mClientController = new ClientController(mPackageManagerInternal);
        synchronized (ImfLock.class) {
            mClientController.addClientControllerCallback(c -> onClientRemoved(c));
            mImeBindingState = ImeBindingState.newEmptyState();
            UserData.initialize(mHandler,
                    /* bindingControllerCreator= */ () -> bindingControllerForTesting != null
                            ? bindingControllerForTesting
                            : new InputMethodBindingController(this));
        }

        mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
@@ -1732,9 +1736,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub

            // Check if selected IME of current user supports handwriting.
            if (userId == mCurrentUserId) {
                return mBindingController.supportsStylusHandwriting()
                final UserData userData = UserData.getOrCreate(userId);
                final InputMethodBindingController bindingController = userData.mBindingController;
                return bindingController.supportsStylusHandwriting()
                        && (!connectionless
                                || mBindingController.supportsConnectionlessStylusHandwriting());
                                || bindingController.supportsConnectionlessStylusHandwriting());
            }
            final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
            final InputMethodInfo imi = settings.getMethodMap().get(
@@ -2063,7 +2069,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
                curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker();
        final SparseArray<IAccessibilityInputMethodSession> accessibilityInputMethodSessions =
                createAccessibilityInputMethodSessions(mCurClient.mAccessibilitySessions);
        if (mBindingController.supportsStylusHandwriting() && hasSupportedStylusLocked()) {
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        if (userData.mBindingController.supportsStylusHandwriting() && hasSupportedStylusLocked()) {
            mHwController.setInkWindowInitializer(new InkWindowInitializer());
        }
        return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
@@ -2178,13 +2185,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        mCurEditorInfo = editorInfo;

        // If configured, we want to avoid starting up the IME if it is not supposed to be showing
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        if (shouldPreventImeStartupLocked(selectedMethodId, startInputFlags,
                unverifiedTargetSdkVersion)) {
            if (DEBUG) {
                Slog.d(TAG, "Avoiding IME startup and unbinding current input method.");
            }
            invalidateAutofillSessionLocked();
            mBindingController.unbindCurrentMethod();
            userData.mBindingController.unbindCurrentMethod();
            return InputBindResult.NO_EDITOR;
        }

@@ -2216,9 +2224,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
            }
        }

        mBindingController.unbindCurrentMethod();

        return mBindingController.bindCurrentMethod();
        userData.mBindingController.unbindCurrentMethod();
        return userData.mBindingController.bindCurrentMethod();
    }

    /**
@@ -2481,7 +2488,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        setSelectedMethodIdLocked(null);
        // Callback before clean-up binding states.
        onUnbindCurrentMethodByReset();
        mBindingController.unbindCurrentMethod();
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        userData.mBindingController.unbindCurrentMethod();
        unbindCurrentClientLocked(unbindClientReason);
    }

@@ -3113,7 +3121,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
            @Nullable String delegatorPackageName,
            @NonNull IConnectionlessHandwritingCallback callback) throws RemoteException {
        synchronized (ImfLock.class) {
            if (!mBindingController.supportsConnectionlessStylusHandwriting()) {
            final UserData userData = UserData.getOrCreate(mCurrentUserId);
            if (!userData.mBindingController.supportsConnectionlessStylusHandwriting()) {
                Slog.w(TAG, "Connectionless stylus handwriting mode unsupported by IME.");
                callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED);
                return;
@@ -3179,9 +3188,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
                            + " startStylusHandwriting()");
                    return false;
                }
                final UserData userData = UserData.getOrCreate(mCurrentUserId);
                final long ident = Binder.clearCallingIdentity();
                try {
                    if (!mBindingController.supportsStylusHandwriting()) {
                    if (!userData.mBindingController.supportsStylusHandwriting()) {
                        Slog.w(TAG,
                                "Stylus HW unsupported by IME. Ignoring startStylusHandwriting()");
                        return false;
@@ -3360,7 +3370,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        mVisibilityStateComputer.requestImeVisibility(windowToken, true);

        // Ensure binding the connection when IME is going to show.
        mBindingController.setCurrentMethodVisible();
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        userData.mBindingController.setCurrentMethodVisible();
        final IInputMethodInvoker curMethod = getCurMethodLocked();
        ImeTracker.forLogging().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
        if (curMethod != null) {
@@ -3463,7 +3474,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        } else {
            ImeTracker.forLogging().onCancelled(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
        }
        mBindingController.setCurrentMethodNotVisible();
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        userData.mBindingController.setCurrentMethodNotVisible();
        mVisibilityStateComputer.clearImeShowFlags();
        // Cancel existing statsToken for show IME as we got a hide request.
        ImeTracker.forLogging().onCancelled(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
@@ -3745,7 +3757,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
                // Note that we can trust client's display ID as long as it matches
                // to the display ID obtained from the window.
                if (cs.mSelfReportedDisplayId != mCurTokenDisplayId) {
                    mBindingController.unbindCurrentMethod();
                    final UserData userData = UserData.getOrCreate(userId);
                    userData.mBindingController.unbindCurrentMethod();
                }
            }
        }
@@ -4201,6 +4214,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        }, mHandler);
    }

    @GuardedBy("ImfLock.class")
    private void addStylusDeviceIdLocked(int deviceId) {
        if (mStylusIds == null) {
            mStylusIds = new IntArray();
@@ -4211,8 +4225,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        mStylusIds.add(deviceId);
        // a new Stylus is detected. If IME supports handwriting, and we don't have
        // handwriting initialized, lets do it now.
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        final InputMethodBindingController bindingController = userData.mBindingController;
        if (!mHwController.getCurrentRequestId().isPresent()
                && mBindingController.supportsStylusHandwriting()) {
                && bindingController.supportsStylusHandwriting()) {
            scheduleResetStylusHandwriting();
        }
    }
@@ -4788,7 +4804,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub

            case MSG_RESET_HANDWRITING: {
                synchronized (ImfLock.class) {
                    if (mBindingController.supportsStylusHandwriting()
                    final UserData userData = UserData.getOrCreate(mCurrentUserId);
                    if (userData.mBindingController.supportsStylusHandwriting()
                            && getCurMethodLocked() != null && hasSupportedStylusLocked()) {
                        Slog.d(TAG, "Initializing Handwriting Spy");
                        mHwController.initializeHandwritingSpy(mCurTokenDisplayId);
@@ -4813,11 +4830,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
                    if (curMethod == null || mImeBindingState.mFocusedWindow == null) {
                        return true;
                    }
                    final UserData userData = UserData.getOrCreate(mCurrentUserId);
                    final HandwritingModeController.HandwritingSession session =
                            mHwController.startHandwritingSession(
                                    msg.arg1 /*requestId*/,
                                    msg.arg2 /*pid*/,
                                    mBindingController.getCurMethodUid(),
                                    userData.mBindingController.getCurMethodUid(),
                                    mImeBindingState.mFocusedWindow);
                    if (session == null) {
                        Slog.e(TAG,
@@ -5111,7 +5129,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub

    @GuardedBy("ImfLock.class")
    void sendOnNavButtonFlagsChangedLocked() {
        final IInputMethodInvoker curMethod = mBindingController.getCurMethod();
        final UserData userData = UserData.getOrCreate(mCurrentUserId);
        final IInputMethodInvoker curMethod = userData.mBindingController.getCurMethod();
        if (curMethod == null) {
            // No need to send the data if the IME is not yet bound.
            return;
@@ -5868,9 +5887,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
            p.println("  mCurClient=" + client + " mCurSeq=" + getSequenceNumberLocked());
            p.println("  mFocusedWindowPerceptible=" + mFocusedWindowPerceptible);
            mImeBindingState.dump("  ", p);
            final UserData userData = UserData.getOrCreate(mCurrentUserId);
            p.println("  mCurId=" + getCurIdLocked() + " mHaveConnection=" + hasConnectionLocked()
                    + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound="
                    + mBindingController.isVisibleBound());
                    + userData.mBindingController.isVisibleBound());
            p.println("  mCurToken=" + getCurTokenLocked());
            p.println("  mCurTokenDisplayId=" + mCurTokenDisplayId);
            p.println("  mCurHostInputToken=" + mCurHostInputToken);
@@ -6364,7 +6384,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
                    if (userId == mCurrentUserId) {
                        hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */,
                                SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND);
                        mBindingController.unbindCurrentMethod();
                        final UserData userData = UserData.getOrCreate(mCurrentUserId);
                        userData.mBindingController.unbindCurrentMethod();

                        // Enable default IMEs, disable others
                        var toDisable = settings.getEnabledInputMethodList();
+21 −10
Original line number Diff line number Diff line
@@ -28,8 +28,10 @@ import com.android.server.pm.UserManagerInternal;

final class UserData {

    @NonNull
    private static final SparseArray<UserData> sPerUserMonitor = new SparseArray<>();
    private static SparseArray<UserData> sUserData;

    @GuardedBy("ImfLock.class")
    private static InputMethodBindingController.Creator sBindingControllerCreator;

    @UserIdInt
    final int mUserId;
@@ -37,24 +39,33 @@ final class UserData {
    @GuardedBy("ImfLock.class")
    final Sequence mSequence = new Sequence();

    @NonNull
    final InputMethodBindingController mBindingController;

    /**
     * Not intended to be instantiated.
     */
    private UserData(int userId) {
    private UserData(int userId,
            InputMethodBindingController bindingController) {
        mUserId = userId;
        mBindingController = bindingController;
    }

    @GuardedBy("ImfLock.class")
    static UserData getOrCreate(@UserIdInt int userId) {
        UserData monitor = sPerUserMonitor.get(userId);
        if (monitor == null) {
            monitor = new UserData(userId);
            sPerUserMonitor.put(userId, monitor);
        UserData userData = sUserData.get(userId);
        if (userData == null) {
            userData = new UserData(userId, sBindingControllerCreator.create());
            sUserData.put(userId, userData);
        }
        return monitor;
        return userData;
    }

    static void initialize(Handler handler) {
    @GuardedBy("ImfLock.class")
    static void initialize(Handler handler,
            InputMethodBindingController.Creator bindingControllerCreator) {
        sUserData = new SparseArray<>();
        sBindingControllerCreator = bindingControllerCreator;
        final UserManagerInternal userManagerInternal =
                LocalServices.getService(UserManagerInternal.class);
        userManagerInternal.addUserLifecycleListener(
@@ -64,7 +75,7 @@ final class UserData {
                        final int userId = user.id;
                        handler.post(() -> {
                            synchronized (ImfLock.class) {
                                sPerUserMonitor.remove(userId);
                                sUserData.remove(userId);
                            }
                        });
                    }