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

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

Add InputMethodManagerDelegate#getLockObject

As CL[1] introduces per-window based ImeFocusController for handling
the IME served view focus update logic.

However, for InputMethodManager APIs requires to access
ImeFocusController#{mServedView, mNextServedView} for starting the input
connection or checking the caller's validity, which needs a lock for
thread safety.

As a result, it would make sense to expose mH for ImeFocusController
through an new method InputMethodManagerDelegate#getLockObject
to protect the data consistancy during InputMethodMananger APIs
invoking to access the served view.

Also, renaming the methods (and update the javadoc) with "Locked" sufix:
- ImeFocusController#get{Served, NextServed}View
- ImeFocusController#set{Served, NextServed}View

Note that this is a refactoring preperation CL with added a TODO that
will use getLockObject in the follow-up CL.

[1]: Ib455704fe1e9d243f93190a84f230210dbceac2a

Bug: 244504062
Test: atest CtsInputMethodTestCases
Change-Id: I9c072b829d1db1e68b65e766d764ee71cb16e6a2
parent 4a8abca2
Loading
Loading
Loading
Loading
+40 −4
Original line number Original line Diff line number Diff line
@@ -43,8 +43,21 @@ public final class ImeFocusController {


    private final ViewRootImpl mViewRootImpl;
    private final ViewRootImpl mViewRootImpl;
    private boolean mHasImeFocus = false;
    private boolean mHasImeFocus = false;

    /**
     * This is the view that should currently be served by an input method,
     * regardless of the state of setting that up.
     * @see InputMethodManagerDelegate#getLockObject()
     */
    private View mServedView;
    private View mServedView;

    /**
     * This is the next view that will be served by the input method, when
     * we get around to updating things.
     * @see InputMethodManagerDelegate#getLockObject()
     */
    private View mNextServedView;
    private View mNextServedView;

    private InputMethodManagerDelegate mDelegate;
    private InputMethodManagerDelegate mDelegate;


    @UiThread
    @UiThread
@@ -284,21 +297,44 @@ public final class ImeFocusController {
        boolean isCurrentRootView(ViewRootImpl rootView);
        boolean isCurrentRootView(ViewRootImpl rootView);
        boolean isRestartOnNextWindowFocus(boolean reset);
        boolean isRestartOnNextWindowFocus(boolean reset);
        boolean hasActiveConnection(View view);
        boolean hasActiveConnection(View view);

        /**
         * 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();
    }
    }


    public View getServedView() {
    /**
     * Returns The current IME served view for {@link InputMethodManager}.
     * Used to start input connection or check the caller's validity when calling
     * {@link InputMethodManager} APIs.
     * Note that this method requires to be called inside {@code InputMethodManager#mH} lock for
     * data consistency.
     */
    public View getServedViewLocked() {
        return mServedView;
        return mServedView;
    }
    }


    public View getNextServedView() {
    /**
     * Returns The next incoming IME served view for {@link InputMethodManager}.
     * Note that this method requires to be called inside {@code InputMethodManager#mH} lock for
     * data consistency.
     */
    public View getNextServedViewLocked() {
        return mNextServedView;
        return mNextServedView;
    }
    }


    public void setServedView(View view) {
    // TODO(b/244504062): Remove this method dependency from InputMethodManager.
    public void setServedViewLocked(View view) {
        mServedView = view;
        mServedView = view;
    }
    }


    public void setNextServedView(View view) {
    // TODO(b/244504062): Remove this method dependency from InputMethodManager.
    public void setNextServedViewLocked(View view) {
        mNextServedView = view;
        mNextServedView = view;
    }
    }


+1 −4
Original line number Original line Diff line number Diff line
@@ -838,11 +838,8 @@ public class BaseInputConnection implements InputConnection {
            Context context;
            Context context;
            if (mTargetView != null) {
            if (mTargetView != null) {
                context = mTargetView.getContext();
                context = mTargetView.getContext();
            } else if (mIMM.mCurRootView != null) {
                final View servedView = mIMM.mCurRootView.getImeFocusController().getServedView();
                context = servedView != null ? servedView.getContext() : null;
            } else {
            } else {
                context = null;
                context = mIMM.getFallbackContextFromServedView();
            }
            }
            if (context != null) {
            if (context != null) {
                TypedArray ta = context.getTheme()
                TypedArray ta = context.getTheme()
+31 −5
Original line number Original line Diff line number Diff line
@@ -677,6 +677,21 @@ public final class InputMethodManager {
        return fallbackImm;
        return fallbackImm;
    }
    }


    /**
     * An internal API that returns the {@link Context} of the current served view connected to
     * an input method.
     * @hide
     */
    Context getFallbackContextFromServedView() {
        synchronized (mH) {
            if (mCurRootView == null) {
                return null;
            }
            final View servedView = mCurRootView.getImeFocusController().getServedViewLocked();
            return servedView != null ? servedView.getContext() : null;
        }
    }

    private static boolean canStartInput(View servedView) {
    private static boolean canStartInput(View servedView) {
        // We can start input ether the servedView has window focus
        // We can start input ether the servedView has window focus
        // or the activity is showing autofill ui.
        // or the activity is showing autofill ui.
@@ -786,7 +801,7 @@ public final class InputMethodManager {
            synchronized (mH) {
            synchronized (mH) {
                // For some reason we didn't do a startInput + windowFocusGain, so
                // For some reason we didn't do a startInput + windowFocusGain, so
                // we'll just do a window focus gain and call it a day.
                // we'll just do a window focus gain and call it a day.
                View servedView = controller.getServedView();
                View servedView = controller.getServedViewLocked();
                boolean nextFocusHasConnection = servedView != null && servedView == focusedView
                boolean nextFocusHasConnection = servedView != null && servedView == focusedView
                        && hasActiveConnection(focusedView);
                        && hasActiveConnection(focusedView);
                if (DEBUG) {
                if (DEBUG) {
@@ -878,6 +893,16 @@ public final class InputMethodManager {
                        && mServedInputConnection.getServedView() == view;
                        && mServedInputConnection.getServedView() == view;
            }
            }
        }
        }

        /**
         * Returns the {@link InputMethodManager#mH} lock object.
         * Used for {@link ImeFocusController} to guard the served view being accessed by
         * {@link InputMethodManager} in different threads.
         */
        @Override
        public Object getLockObject() {
            return mH;
        }
    }
    }


    /** @hide */
    /** @hide */
@@ -898,26 +923,27 @@ public final class InputMethodManager {


    @GuardedBy("mH")
    @GuardedBy("mH")
    private View getServedViewLocked() {
    private View getServedViewLocked() {
        return mCurRootView != null ? mCurRootView.getImeFocusController().getServedView() : null;
        return mCurRootView != null ? mCurRootView.getImeFocusController().getServedViewLocked()
                : null;
    }
    }


    @GuardedBy("mH")
    @GuardedBy("mH")
    private View getNextServedViewLocked() {
    private View getNextServedViewLocked() {
        return mCurRootView != null ? mCurRootView.getImeFocusController().getNextServedView()
        return mCurRootView != null ? mCurRootView.getImeFocusController().getNextServedViewLocked()
                : null;
                : null;
    }
    }


    @GuardedBy("mH")
    @GuardedBy("mH")
    private void setServedViewLocked(View view) {
    private void setServedViewLocked(View view) {
        if (mCurRootView != null) {
        if (mCurRootView != null) {
            mCurRootView.getImeFocusController().setServedView(view);
            mCurRootView.getImeFocusController().setServedViewLocked(view);
        }
        }
    }
    }


    @GuardedBy("mH")
    @GuardedBy("mH")
    private void setNextServedViewLocked(View view) {
    private void setNextServedViewLocked(View view) {
        if (mCurRootView != null) {
        if (mCurRootView != null) {
            mCurRootView.getImeFocusController().setNextServedView(view);
            mCurRootView.getImeFocusController().setNextServedViewLocked(view);
        }
        }
    }
    }