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

Commit 85a96259 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I93352621,I8357bfaf,Ibcde3576,I9c072b82

* changes:
  Remove InputMethodManagerDelegate#isRestartOnNextWindowFocus
  Use getLockObject to sync ImeFocusController#{mServedView, mNextServedView}
  Remove ImeFocusController#set{Served, NextServed}View
  Add InputMethodManagerDelegate#getLockObject
parents aa3379f0 786f31f2
Loading
Loading
Loading
Loading
+142 −71
Original line number Diff line number Diff line
@@ -43,8 +43,21 @@ public final class ImeFocusController {

    private final ViewRootImpl mViewRootImpl;
    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;

    /**
     * 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 InputMethodManagerDelegate mDelegate;

    @UiThread
@@ -123,37 +136,43 @@ public final class ImeFocusController {

        boolean forceFocus = false;
        final InputMethodManagerDelegate immDelegate = getImmDelegate();
        if (immDelegate.isRestartOnNextWindowFocus(true /* reset */)) {
            if (DEBUG) Log.v(TAG, "Restarting due to isRestartOnNextWindowFocus as true");
            forceFocus = true;
        }

        synchronized (immDelegate.getLockObject()) {
            // 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,
        immDelegate.startInputOnWindowFocusGain(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 (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
            if (mServedView == mNextServedView && !forceNewFocus) {
                return false;
            }
            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();
@@ -162,6 +181,7 @@ public final class ImeFocusController {
            }
            mServedView = mNextServedView;
            immDelegate.finishComposingText();
        }

        if (startInput) {
            immDelegate.startInput(StartInputReason.CHECK_FOCUS, null /* focusedView */,
@@ -175,14 +195,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
@@ -194,12 +218,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) {
@@ -209,10 +236,12 @@ public final class ImeFocusController {
                mViewRootImpl.dispatchCheckFocus();
            }
        }
    }

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

@@ -270,10 +300,22 @@ 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);
        void startInputAsyncOnWindowFocusGain(View rootView,
        /**
         * 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 startInputOnWindowFocusGain(View rootView,
                @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags,
                boolean forceNewFocus);
        void finishInput();
@@ -282,24 +324,53 @@ public final class ImeFocusController {
        void finishComposingText();
        void setCurrentRootView(ViewRootImpl rootView);
        boolean isCurrentRootView(ViewRootImpl rootView);
        boolean isRestartOnNextWindowFocus(boolean reset);
        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.
         */
        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;
    }

    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;
    }

    public void setServedView(View view) {
        mServedView = view;
    /**
     * Clears the served & the next served view when the controller triggers
     * {@link InputMethodManagerDelegate#finishInput()} or
     * {@link InputMethodManagerDelegate#finishInputAndReportToIme()}.
     * Note that this method requires to be called inside {@code InputMethodManager#mH} lock for
     * data consistency.
     *
     * @return The {@code mServedView} that has cleared, or {@code null} means nothing to clear.
     */
    public View clearServedViewsLocked() {
        View clearedView = null;
        mNextServedView = null;
        if (mServedView != null) {
            clearedView = mServedView;
            mServedView = null;
        }

    public void setNextServedView(View view) {
        mNextServedView = view;
        return clearedView;
    }

    /**
+1 −4
Original line number Diff line number Diff line
@@ -879,11 +879,8 @@ public class BaseInputConnection implements InputConnection {
            Context context;
            if (mTargetView != null) {
                context = mTargetView.getContext();
            } else if (mIMM.mCurRootView != null) {
                final View servedView = mIMM.mCurRootView.getImeFocusController().getServedView();
                context = servedView != null ? servedView.getContext() : null;
            } else {
                context = null;
                context = mIMM.getFallbackContextFromServedView();
            }
            if (context != null) {
                TypedArray ta = context.getTheme()
+44 −37
Original line number Diff line number Diff line
@@ -677,6 +677,21 @@ public final class InputMethodManager {
        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) {
        // We can start input ether the servedView has window focus
        // or the activity is showing autofill ui.
@@ -756,10 +771,10 @@ public final class InputMethodManager {
        }

        /**
         * For {@link ImeFocusController} to start input asynchronously when focus gain.
         * For {@link ImeFocusController} to start input when gaining the window focus.
         */
        @Override
        public void startInputAsyncOnWindowFocusGain(View focusedView,
        public void startInputOnWindowFocusGain(View focusedView,
                @SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus) {
            int startInputFlags = getStartInputFlags(focusedView, 0);
            startInputFlags |= StartInputFlags.WINDOW_GAINED_FOCUS;
@@ -772,6 +787,15 @@ public final class InputMethodManager {
            if (controller == null) {
                return;
            }

            synchronized (mH) {
                if (mRestartOnNextWindowFocus) {
                    if (DEBUG) Log.v(TAG, "Restarting due to mRestartOnNextWindowFocus as true");
                    mRestartOnNextWindowFocus = false;
                    forceNewFocus = true;
                }
            }

            if (controller.checkFocus(forceNewFocus, false)) {
                // We need to restart input on the current focus view.  This
                // should be done in conjunction with telling the system service
@@ -786,7 +810,7 @@ public final class InputMethodManager {
            synchronized (mH) {
                // For some reason we didn't do a startInput + windowFocusGain, so
                // 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
                        && hasActiveInputConnectionInternal(focusedView);
                if (DEBUG) {
@@ -844,20 +868,6 @@ public final class InputMethodManager {
            }
        }

        /**
         * For {@link ImeFocusController#checkFocus} if needed to force check new focus.
         */
        @Override
        public boolean isRestartOnNextWindowFocus(boolean reset) {
            synchronized (mH) {
                final boolean result = mRestartOnNextWindowFocus;
                if (reset) {
                    mRestartOnNextWindowFocus = false;
                }
                return result;
            }
        }

        /**
         * Checks whether the active input connection (if any) is for the given view.
         *
@@ -867,6 +877,16 @@ public final class InputMethodManager {
        public boolean hasActiveConnection(View view) {
            return hasActiveInputConnectionInternal(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 */
@@ -907,29 +927,16 @@ public final class InputMethodManager {

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

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

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

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

    private ImeFocusController getFocusController() {
        synchronized (mH) {
            if (mCurRootView != null) {
@@ -1776,13 +1783,13 @@ public final class InputMethodManager {
    @GuardedBy("mH")
    void finishInputLocked() {
        mVirtualDisplayToScreenMatrix = null;
        setNextServedViewLocked(null);
        if (getServedViewLocked() != null) {
        final ImeFocusController controller = getFocusController();
        final View clearedView = controller != null ? controller.clearServedViewsLocked() : null;
        if (clearedView != null) {
            if (DEBUG) {
                Log.v(TAG, "FINISH INPUT: mServedView="
                        + InputMethodDebug.dumpViewInfo(getServedViewLocked()));
                        + InputMethodDebug.dumpViewInfo(clearedView));
            }
            setServedViewLocked(null);
            mCompletions = null;
            mServedConnecting = false;
            clearConnectionLocked();