Remove InputMethodManagerDelegate#getLockObject()

This is a follow up CL to our previous CL [1], which introduced

  InputMethodManagerDelegate#getLockObject()

to clarify that "mServedView" and "mNextServedView" need to be guarded
with

  InputMethodManager#mH

as a short term workaround.

With this CL, above two fields are moved back to InputMethodManager
like they used to be before we introduce ImeFocusController [2].

This is a mostly mechanical refactoring.  Hopefully there should be no
observable behavior change.

 [1]: I9c072b829d1db1e68b65e766d764ee71cb16e6a2
      31e467846378c12ca51c92cc4cc35e59d495288d
 [2]: Ib455704fe1e9d243f93190a84f230210dbceac2a
      970d9d2e0c979cf9a0ff0a79ef49044ed1363d4f

Bug: 244504062
Test: presubmit
Change-Id: Ie3446e1d0f62c489195e31fc7f073020884d6cae
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index d4875d4..1afd048 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -17,8 +17,6 @@
 package android.view;
 
 import static android.view.ImeFocusControllerProto.HAS_IME_FOCUS;
-import static android.view.ImeFocusControllerProto.NEXT_SERVED_VIEW;
-import static android.view.ImeFocusControllerProto.SERVED_VIEW;
 
 import android.annotation.AnyThread;
 import android.annotation.NonNull;
@@ -31,8 +29,6 @@
 import com.android.internal.inputmethod.StartInputFlags;
 import com.android.internal.inputmethod.StartInputReason;
 
-import java.util.Objects;
-
 /**
  * Responsible for IME focus handling inside {@link ViewRootImpl}.
  * @hide
@@ -43,21 +39,6 @@
 
     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
@@ -134,122 +115,30 @@
                     windowAttribute.softInputMode));
         }
 
-        boolean forceFocus = false;
-        final InputMethodManagerDelegate immDelegate = getImmDelegate();
-        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.
-            final boolean nextFocusIsServedView = mServedView == viewForWindowFocus;
-
-            if (nextFocusIsServedView && !immDelegate.hasActiveConnection(viewForWindowFocus)) {
-                forceFocus = true;
-            }
-        }
-
-        immDelegate.startInputOnWindowFocusGain(viewForWindowFocus,
-                windowAttribute.softInputMode, windowAttribute.flags, forceFocus);
+        getImmDelegate().onPostWindowFocus(viewForWindowFocus, windowAttribute);
     }
 
     /**
      * @see InputMethodManager#checkFocus()
      */
     public boolean checkFocus(boolean forceNewFocus, boolean startInput) {
-        final InputMethodManagerDelegate immDelegate = getImmDelegate();
-        synchronized (immDelegate.getLockObject()) {
-            if (!immDelegate.isCurrentRootView(mViewRootImpl)) {
-                return false;
-            }
-            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>"));
-            }
-            // Close the connection when no next served view coming.
-            if (mNextServedView == null) {
-                immDelegate.finishInput();
-                immDelegate.closeCurrentIme();
-                return false;
-            }
-            mServedView = mNextServedView;
-            immDelegate.finishComposingText();
-        }
-
-        if (startInput) {
-            immDelegate.startInput(StartInputReason.CHECK_FOCUS, null /* focusedView */,
-                    0 /* startInputFlags */, 0 /* softInputMode */, 0 /* windowFlags */);
-        }
-        return true;
+        return getImmDelegate().checkFocus(forceNewFocus, startInput, mViewRootImpl);
     }
 
     @UiThread
     void onViewFocusChanged(View view, boolean hasFocus) {
-        if (view == null || view.isTemporarilyDetached()) {
-            return;
-        }
-        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)
-                        + ", 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
-            //    at this moment isn't the right way.
-            // 2) We only care about the served view change when it focused, since changing input
-            //    connection when the focus target changed is reasonable.
-            // 3) Setting the next served view as null when no more served view should be handled in
-            //    other special events (e.g. view detached from window or the window dismissed).
-            if (hasFocus) {
-                mNextServedView = view;
-            }
-        }
-        mViewRootImpl.dispatchCheckFocus();
+        getImmDelegate().onViewFocusChanged(view, hasFocus);
     }
 
     @UiThread
     void onViewDetachedFromWindow(View view) {
-        final InputMethodManagerDelegate immDelegate = getImmDelegate();
-        synchronized (immDelegate.getLockObject()) {
-            if (!immDelegate.isCurrentRootView(view.getViewRootImpl())) {
-                return;
-            }
-            if (mNextServedView == view) {
-                mNextServedView = null;
-            }
-            if (mServedView == view) {
-                mViewRootImpl.dispatchCheckFocus();
-            }
-        }
+        getImmDelegate().onViewDetachedFromWindow(view, mViewRootImpl);
+
     }
 
     @UiThread
     void onWindowDismissed() {
-        final InputMethodManagerDelegate immDelegate = getImmDelegate();
-        synchronized (immDelegate.getLockObject()) {
-            if (!immDelegate.isCurrentRootView(mViewRootImpl)) {
-                return;
-            }
-            if (mServedView != null) {
-                immDelegate.finishInput();
-            }
-            immDelegate.setCurrentRootView(null);
-        }
+        getImmDelegate().onWindowDismissed(mViewRootImpl);
         mHasImeFocus = false;
     }
 
@@ -302,75 +191,21 @@
     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 startInputOnWindowFocusGain(View rootView,
-                @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags,
-                boolean forceNewFocus);
-        void finishInput();
+
+        void onPostWindowFocus(View viewForWindowFocus,
+                @NonNull WindowManager.LayoutParams windowAttribute);
+        void onViewFocusChanged(@NonNull View view, boolean hasFocus);
+        boolean checkFocus(boolean forceNewFocus, boolean startInput, ViewRootImpl viewRootImpl);
+        void onViewDetachedFromWindow(View view, ViewRootImpl viewRootImpl);
+        void onWindowDismissed(ViewRootImpl viewRootImpl);
+
         void finishInputAndReportToIme();
-        void closeCurrentIme();
-        void finishComposingText();
         void setCurrentRootView(ViewRootImpl rootView);
         boolean isCurrentRootView(ViewRootImpl rootView);
-        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();
-    }
-
-    /**
-     * 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;
-    }
-
-    /**
-     * 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;
-    }
-
-    /**
-     * 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;
-        }
-        return clearedView;
     }
 
     /**
@@ -384,8 +219,6 @@
     void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(HAS_IME_FOCUS, mHasImeFocus);
-        proto.write(SERVED_VIEW, Objects.toString(mServedView));
-        proto.write(NEXT_SERVED_VIEW, Objects.toString(mNextServedView));
         proto.end(token);
     }
 }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index c1fe686..a2a9209 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -92,6 +92,7 @@
 import android.view.View;
 import android.view.ViewRootImpl;
 import android.view.WindowInsets;
+import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
@@ -457,6 +458,22 @@
     // -----------------------------------------------------------
 
     /**
+     * This is the view that should currently be served by an input method,
+     * regardless of the state of setting that up.
+     */
+    @Nullable
+    @GuardedBy("mH")
+    private View mServedView;
+
+    /**
+     * This is the next view that will be served by the input method, when
+     * we get around to updating things.
+     */
+    @Nullable
+    @GuardedBy("mH")
+    private View mNextServedView;
+
+    /**
      * This is the root view of the overall window that currently has input
      * method focus.
      */
@@ -691,8 +708,7 @@
             if (mCurRootView == null) {
                 return null;
             }
-            final View servedView = mCurRootView.getImeFocusController().getServedViewLocked();
-            return servedView != null ? servedView.getContext() : null;
+            return mServedView != null ? mServedView.getContext() : null;
         }
     }
 
@@ -727,11 +743,7 @@
                     startInputFlags, softInputMode, windowFlags);
         }
 
-        /**
-         * Used by {@link ImeFocusController} to finish input connection.
-         */
-        @Override
-        public void finishInput() {
+        private void finishInput() {
             ImeTracing.getInstance().triggerClientDump(
                     "InputMethodManager.DelegateImpl#finishInput", InputMethodManager.this,
                     null /* icProto */);
@@ -760,19 +772,28 @@
             }
         }
 
-        /**
-         * Used by {@link ImeFocusController} to hide current input method editor.
-         */
         @Override
-        public void closeCurrentIme() {
-            closeCurrentInput();
+        public void onPostWindowFocus(View viewForWindowFocus,
+                @NonNull WindowManager.LayoutParams windowAttribute) {
+            boolean forceFocus = false;
+            synchronized (mH) {
+                // 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.
+                final boolean nextFocusIsServedView = mServedView == viewForWindowFocus;
+
+                if (nextFocusIsServedView
+                        && !hasActiveInputConnectionInternal(viewForWindowFocus)) {
+                    forceFocus = true;
+                }
+            }
+            startInputOnWindowFocusGain(viewForWindowFocus,
+                    windowAttribute.softInputMode, windowAttribute.flags, forceFocus);
         }
 
-        /**
-         * For {@link ImeFocusController} to start input when gaining the window focus.
-         */
-        @Override
-        public void startInputOnWindowFocusGain(View focusedView,
+        private void startInputOnWindowFocusGain(View focusedView,
                 @SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus) {
             int startInputFlags = getStartInputFlags(focusedView, 0);
             startInputFlags |= StartInputFlags.WINDOW_GAINED_FOCUS;
@@ -808,8 +829,7 @@
             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.getServedViewLocked();
-                boolean nextFocusHasConnection = servedView != null && servedView == focusedView
+                boolean nextFocusHasConnection = mServedView != null && mServedView == focusedView
                         && hasActiveInputConnectionInternal(focusedView);
                 if (DEBUG) {
                     Log.v(TAG, "Reporting focus gain, without startInput"
@@ -831,16 +851,102 @@
             }
         }
 
-        /**
-         * Used by {@link ImeFocusController} to finish current composing text.
-         */
         @Override
-        public void finishComposingText() {
+        public void onViewFocusChanged(@Nullable View view, boolean hasFocus) {
+            if (view == null || view.isTemporarilyDetached()) {
+                return;
+            }
+            final ViewRootImpl viewRootImpl = view.getViewRootImpl();
             synchronized (mH) {
+                if (mCurRootView != viewRootImpl) {
+                    return;
+                }
+                if (!view.hasImeFocus() || !view.hasWindowFocus()) {
+                    return;
+                }
+                if (DEBUG) {
+                    Log.d(TAG, "onViewFocusChanged, view=" + InputMethodDebug.dumpViewInfo(view));
+                }
+
+                // 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 at this moment isn't the right way.
+                // 2) We only care about the served view change when it focused, since changing
+                //    input connection when the focus target changed is reasonable.
+                // 3) Setting the next served view as null when no more served view should be
+                //    handled in other special events (e.g. view detached from window or the window
+                //    dismissed).
+                if (hasFocus) {
+                    mNextServedView = view;
+                }
+            }
+            viewRootImpl.dispatchCheckFocus();
+        }
+
+        @Override
+        public boolean checkFocus(boolean forceNewFocus, boolean startInput,
+                ViewRootImpl viewRootImpl) {
+            synchronized (mH) {
+                if (mCurRootView != viewRootImpl) {
+                    return false;
+                }
+                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>"));
+                }
+                // Close the connection when no next served view coming.
+                if (mNextServedView == null) {
+                    finishInput();
+                    closeCurrentInput();
+                    return false;
+                }
+                mServedView = mNextServedView;
                 if (mServedInputConnection != null) {
                     mServedInputConnection.finishComposingTextFromImm();
                 }
             }
+
+            if (startInput) {
+                startInput(StartInputReason.CHECK_FOCUS, null /* focusedView */,
+                        0 /* startInputFlags */, 0 /* softInputMode */, 0 /* windowFlags */);
+            }
+            return true;
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(View view, ViewRootImpl viewRootImpl) {
+            synchronized (mH) {
+                if (mCurRootView != view.getViewRootImpl()) {
+                    return;
+                }
+                if (mNextServedView == view) {
+                    mNextServedView = null;
+                }
+                if (mServedView == view) {
+                    viewRootImpl.dispatchCheckFocus();
+                }
+            }
+        }
+
+        @Override
+        public void onWindowDismissed(ViewRootImpl viewRootImpl) {
+            synchronized (mH) {
+                if (mCurRootView != viewRootImpl) {
+                    return;
+                }
+                if (mServedView != null) {
+                    finishInput();
+                }
+                setCurrentRootView(null);
+            }
         }
 
         /**
@@ -865,26 +971,6 @@
                 return mCurRootView == rootView;
             }
         }
-
-        /**
-         * Checks whether the active input connection (if any) is for the given view.
-         *
-         * @see #hasActiveInputConnectionInternal(View)}
-         */
-        @Override
-        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 */
@@ -938,14 +1024,12 @@
 
     @GuardedBy("mH")
     private View getServedViewLocked() {
-        return mCurRootView != null ? mCurRootView.getImeFocusController().getServedViewLocked()
-                : null;
+        return mCurRootView != null ? mServedView : null;
     }
 
     @GuardedBy("mH")
     private View getNextServedViewLocked() {
-        return mCurRootView != null ? mCurRootView.getImeFocusController().getNextServedViewLocked()
-                : null;
+        return mCurRootView != null ? mNextServedView : null;
     }
 
     private ImeFocusController getFocusController() {
@@ -1794,8 +1878,12 @@
     @GuardedBy("mH")
     void finishInputLocked() {
         mVirtualDisplayToScreenMatrix = null;
-        final ImeFocusController controller = getFocusController();
-        final View clearedView = controller != null ? controller.clearServedViewsLocked() : null;
+        View clearedView = null;
+        mNextServedView = null;
+        if (mServedView != null) {
+            clearedView = mServedView;
+            mServedView = null;
+        }
         if (clearedView != null) {
             if (DEBUG) {
                 Log.v(TAG, "FINISH INPUT: mServedView="