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

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

Use getLockObject to sync ImeFocusController#{mServedView, mNextServedView}

As CL[1] added InputMethodManagerDelegate#getLockObject that used for
protecting mServedView/mNextServedView in ImeFocusController when we
exposed getServedView/getNextServedView for InputMethodManager to access
with thread safty.

Add synchornize block for all places that accessing
{mServedView, mNextServedView} in ImeFocusController.

[1]: I9c072b829d1db1e68b65e766d764ee71cb16e6a2

Bug: 244504062
Test: atest CtsInputMethodTestCases
Change-Id: I8357bfafeaf0a40e3b74eec2fc59a47309451f18
parent 6924863b
Loading
Loading
Loading
Loading
+97 −64
Original line number Diff line number Diff line
@@ -136,6 +136,8 @@ public final class ImeFocusController {

        boolean forceFocus = false;
        final InputMethodManagerDelegate immDelegate = getImmDelegate();
        synchronized (immDelegate.getLockObject()) {
            // TODO(b/244504062): Remove isRestartOnNextWindowFocus.
            if (immDelegate.isRestartOnNextWindowFocus(true /* reset */)) {
                if (DEBUG) Log.v(TAG, "Restarting due to isRestartOnNextWindowFocus as true");
                forceFocus = true;
@@ -144,29 +146,39 @@ public final class ImeFocusController {
            // Update mNextServedView when focusedView changed.
            onViewFocusChanged(viewForWindowFocus, true);

        // Starting new input when the next focused view is same as served view but the currently
        // active connection (if any) is not associated with it.
            // Starting new input when the next focused view is same as served view but the
            // currently active connection (if any) is not associated with it.
            final boolean nextFocusIsServedView = mServedView == viewForWindowFocus;

            if (nextFocusIsServedView && !immDelegate.hasActiveConnection(viewForWindowFocus)) {
                forceFocus = true;
            }
        }

        immDelegate.startInputAsyncOnWindowFocusGain(viewForWindowFocus,
                windowAttribute.softInputMode, windowAttribute.flags, forceFocus);
    }

    /**
     * @see InputMethodManager#checkFocus()
     */
    public boolean checkFocus(boolean forceNewFocus, boolean startInput) {
        final InputMethodManagerDelegate immDelegate = getImmDelegate();
        if (!immDelegate.isCurrentRootView(mViewRootImpl)
                || (mServedView == mNextServedView && !forceNewFocus)) {
        synchronized (immDelegate.getLockObject()) {
            if (!immDelegate.isCurrentRootView(mViewRootImpl)) {
                return false;
            }
            if (mServedView == mNextServedView && !forceNewFocus) {
                return false;
            }
        if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
            if (DEBUG) {
                Log.v(TAG, "checkFocus: view=" + mServedView
                        + " next=" + mNextServedView
                        + " force=" + forceNewFocus
                        + " package="
                + (mServedView != null ? mServedView.getContext().getPackageName() : "<none>"));

                        + (mServedView != null ? mServedView.getContext().getPackageName()
                        : "<none>"));
            }
            // Close the connection when no next served view coming.
            if (mNextServedView == null) {
                immDelegate.finishInput();
@@ -175,6 +187,7 @@ public final class ImeFocusController {
            }
            mServedView = mNextServedView;
            immDelegate.finishComposingText();
        }

        if (startInput) {
            immDelegate.startInput(StartInputReason.CHECK_FOCUS, null /* focusedView */,
@@ -188,14 +201,18 @@ public final class ImeFocusController {
        if (view == null || view.isTemporarilyDetached()) {
            return;
        }
        if (!getImmDelegate().isCurrentRootView(view.getViewRootImpl())) {
        final InputMethodManagerDelegate immDelegate = getImmDelegate();
        synchronized (immDelegate.getLockObject()) {
            if (!immDelegate.isCurrentRootView(view.getViewRootImpl())) {
                return;
            }
            if (!view.hasImeFocus() || !view.hasWindowFocus()) {
                return;
            }
        if (DEBUG) Log.d(TAG, "onViewFocusChanged, view=" + InputMethodDebug.dumpViewInfo(view)
            if (DEBUG) {
                Log.d(TAG, "onViewFocusChanged, view=" + InputMethodDebug.dumpViewInfo(view)
                        + ", mServedView=" + InputMethodDebug.dumpViewInfo(mServedView));
            }

            // We don't need to track the next served view when the view lost focus here because:
            // 1) The current view focus may be cleared temporary when in touch mode, closing input
@@ -207,12 +224,15 @@ public final class ImeFocusController {
            if (hasFocus) {
                mNextServedView = view;
            }
        }
        mViewRootImpl.dispatchCheckFocus();
    }

    @UiThread
    void onViewDetachedFromWindow(View view) {
        if (!getImmDelegate().isCurrentRootView(view.getViewRootImpl())) {
        final InputMethodManagerDelegate immDelegate = getImmDelegate();
        synchronized (immDelegate.getLockObject()) {
            if (!immDelegate.isCurrentRootView(view.getViewRootImpl())) {
                return;
            }
            if (mNextServedView == view) {
@@ -222,10 +242,12 @@ public final class ImeFocusController {
                mViewRootImpl.dispatchCheckFocus();
            }
        }
    }

    @UiThread
    void onWindowDismissed() {
        final InputMethodManagerDelegate immDelegate = getImmDelegate();
        synchronized (immDelegate.getLockObject()) {
            if (!immDelegate.isCurrentRootView(mViewRootImpl)) {
                return;
            }
@@ -233,6 +255,7 @@ public final class ImeFocusController {
                immDelegate.finishInput();
            }
            immDelegate.setCurrentRootView(null);
        }
        mHasImeFocus = false;
    }

@@ -283,9 +306,21 @@ public final class ImeFocusController {
     * @hide
     */
    public interface InputMethodManagerDelegate {
        /**
         * Starts the input connection.
         * Note that this method must not hold the {@link InputMethodManager} lock with
         * {@link InputMethodManagerDelegate#getLockObject()} while {@link InputMethodManager}
         * calling into app-code in different threads.
         */
        boolean startInput(@StartInputReason int startInputReason, View focusedView,
                @StartInputFlags int startInputFlags,
                @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags);
        /**
         * Starts the input connection when gaining the window focus.
         * Note that this method must not hold the {@link InputMethodManager} lock with
         * {@link InputMethodManagerDelegate#getLockObject()} while {@link InputMethodManager}
         * calling into app-code in different threads.
         */
        void startInputAsyncOnWindowFocusGain(View rootView,
                @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags,
                boolean forceNewFocus);
@@ -302,8 +337,6 @@ public final class ImeFocusController {
         * Returns the {@code InputMethodManager#mH} lock object.
         * Used for {@link ImeFocusController} to guard the served view being accessed by
         * {@link InputMethodManager} in different threads.
         *
         * TODO(b/244504062): Use this to all places requires synchronization in controller.
         */
        Object getLockObject();
    }