Get InputMethodManager in View only if needed

The perf regression found in my initial attempt [1] to instantiate
InputMethodManager (IMM) for each display revieled that when a Window
gained/lost focus,
  getContext().getSystemService(InputMethodManager.class)
gets called for all the View objects that belong to the Window.

This CL introduces a private utility method
  View.notifyFocusChangeToInputMethodManager()
to replace existing unnecessary acquisitions of IMM in View.java,
including the most concerning one View.onWindowFocusChanged().

There should be no negative side-effect in doing this optimization.

LatencyTests results:
  testExpandNotificationsLatency on taimen-userdebug
    without this CL:
      results=[43, 46, 58, 47, 52, 59, 55, 59, 58, 46]
      min: 43.0, max:59.0, avg:54.7, median:53.5, std_dev:5.967
    with this CL:
      results=[41, 58, 55, 59, 60, 67, 51, 55, 55, 55]
      min: 41.0, max:67.0, avg:55.6, median:55.0, std_dev:6.344

 [1]: I7242e765426353672823fcc8277f20ac361930d7
      c53d78e992694e471ddaae73f9a30977db9cdb75

Bug: 115893206
Test: atest ActivityManagerMultiDisplayTests
Test: atest CtsInputMethodTestCases CtsInputMethodServiceHostTestCases
Test: atest FrameworksCoreTests:android.view.inputmethod.InputMethodManagerTest
Test: No perf regression observed in Bug 117434607
Change-Id: I5c64b23c3f5cb16f7f3fb9cdc2be063083566050
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c18187b..29d3742 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7315,17 +7315,16 @@
         // Here we check whether we still need the default focus highlight, and switch it on/off.
         switchDefaultFocusHighlight();
 
-        InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
         if (!gainFocus) {
             if (isPressed()) {
                 setPressed(false);
             }
-            if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
-                imm.focusOut(this);
+            if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
+                notifyFocusChangeToInputMethodManager(false /* hasFocus */);
             }
             onFocusLost();
-        } else if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
-            imm.focusIn(this);
+        } else if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
+            notifyFocusChangeToInputMethodManager(true /* hasFocus */);
         }
 
         invalidate(true);
@@ -7341,6 +7340,26 @@
         notifyEnterOrExitForAutoFillIfNeeded(gainFocus);
     }
 
+    /**
+     * Notify {@link InputMethodManager} about the focus change of the {@link View}.
+     *
+     * <p>Does nothing when {@link InputMethodManager} is not available.</p>
+     *
+     * @param hasFocus {@code true} when the {@link View} is being focused.
+     */
+    private void notifyFocusChangeToInputMethodManager(boolean hasFocus) {
+        final InputMethodManager imm =
+                getContext().getSystemService(InputMethodManager.class);
+        if (imm == null) {
+            return;
+        }
+        if (hasFocus) {
+            imm.focusIn(this);
+        } else {
+            imm.focusOut(this);
+        }
+    }
+
     /** @hide */
     public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) {
         if (canNotifyAutofillEnterExitEvent()) {
@@ -12485,7 +12504,7 @@
         mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
         onFinishTemporaryDetach();
         if (hasWindowFocus() && hasFocus()) {
-            getContext().getSystemService(InputMethodManager.class).focusIn(this);
+            notifyFocusChangeToInputMethodManager(true /* hasFocus */);
         }
         notifyEnterOrExitForAutoFillIfNeeded(true);
     }
@@ -12876,20 +12895,19 @@
      *        focus, false otherwise.
      */
     public void onWindowFocusChanged(boolean hasWindowFocus) {
-        InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
         if (!hasWindowFocus) {
             if (isPressed()) {
                 setPressed(false);
             }
             mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
-            if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) {
-                imm.focusOut(this);
+            if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
+                notifyFocusChangeToInputMethodManager(false /* hasFocus */);
             }
             removeLongPressCallback();
             removeTapCallback();
             onFocusLost();
-        } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) {
-            imm.focusIn(this);
+        } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
+            notifyFocusChangeToInputMethodManager(true /* hasFocus */);
         }
 
         refreshDrawableState();
@@ -17981,10 +17999,7 @@
         rebuildOutline();
 
         if (isFocused()) {
-            InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
-            if (imm != null) {
-                imm.focusIn(this);
-            }
+            notifyFocusChangeToInputMethodManager(true /* hasFocus */);
         }
     }