Merge changes I6b8787a2,Ie4194051 into main

* changes:
  Version-gate IME show/hide async nature
  Add flag for fixing return of show/hide input
diff --git a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
index 2f515fe..3a008aa 100644
--- a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
+++ b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
@@ -323,14 +323,14 @@
     static boolean showSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken,
             @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
             int lastClickToolType, @Nullable ResultReceiver resultReceiver,
-            @SoftInputShowHideReason int reason) {
+            @SoftInputShowHideReason int reason, boolean async) {
         final IInputMethodManager service = getService();
         if (service == null) {
             return false;
         }
         try {
             return service.showSoftInput(client, windowToken, statsToken, flags, lastClickToolType,
-                    resultReceiver, reason);
+                    resultReceiver, reason, async);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -339,14 +339,15 @@
     @AnyThread
     static boolean hideSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken,
             @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
-            @Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+            @Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason,
+            boolean async) {
         final IInputMethodManager service = getService();
         if (service == null) {
             return false;
         }
         try {
             return service.hideSoftInput(client, windowToken, statsToken, flags, resultReceiver,
-                    reason);
+                    reason, async);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -407,7 +408,7 @@
             @Nullable IRemoteInputConnection remoteInputConnection,
             @Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
             int unverifiedTargetSdkVersion, @UserIdInt int userId,
-            @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
+            @NonNull ImeOnBackInvokedDispatcher imeDispatcher, boolean useAsyncShowHideMethod) {
         final IInputMethodManager service = getService();
         if (service == null) {
             return -1;
@@ -416,7 +417,7 @@
             service.startInputOrWindowGainedFocusAsync(startInputReason, client, windowToken,
                     startInputFlags, softInputMode, windowFlags, editorInfo, remoteInputConnection,
                     remoteAccessibilityInputConnection, unverifiedTargetSdkVersion, userId,
-                    imeDispatcher, advanceAngGetStartInputSequenceNumber());
+                    imeDispatcher, advanceAngGetStartInputSequenceNumber(), useAsyncShowHideMethod);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 23d7732..2f649c2 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -56,6 +56,7 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityThread;
 import android.app.PropertyInvalidatedCache;
+import android.app.compat.CompatChanges;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -441,6 +442,36 @@
     public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // This is a bug id.
 
     /**
+     * Use async method for {@link InputMethodManager#showSoftInput(View, int, ResultReceiver)},
+     * {@link InputMethodManager#showSoftInput(View, int)} and
+     * {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int, ResultReceiver)},
+     * {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)} for apps targeting V+.
+     * <p>
+     * Apps can incorrectly rely on {@link InputMethodManager#showSoftInput(View, int)} and
+     * {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)} method return type
+     * to interpret result of a request rather than relying on {@link ResultReceiver}. The return
+     * type of the method was never documented to have accurate info of visibility but few apps
+     * incorrectly rely on it.
+     * <p>
+     * Starting Android V, we use async calls into system_server which returns {@code true} if
+     * method call was made but return type doesn't guarantee execution.
+     * Apps targeting older versions will fallback to existing behavior of calling synchronous
+     * methods which had undocumented result in return type.
+     *
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+    private static final long USE_ASYNC_SHOW_HIDE_METHOD = 352594277L; // This is a bug id.
+
+    /**
+     * Version-gating is guarded by bug-fix flag.
+     */
+    private static final boolean ASYNC_SHOW_HIDE_METHOD_ENABLED =
+            !Flags.compatchangeForZerojankproxy()
+                || CompatChanges.isChangeEnabled(USE_ASYNC_SHOW_HIDE_METHOD);
+
+    /**
      * If {@code true}, avoid calling the
      * {@link com.android.server.inputmethod.InputMethodManagerService InputMethodManagerService}
      * by skipping the call to {@link IInputMethodManager#startInputOrWindowGainedFocus}
@@ -2246,6 +2277,8 @@
      *             {@link View#isFocused view focus}, and its containing window has
      *             {@link View#hasWindowFocus window focus}. Otherwise the call fails and
      *             returns {@code false}.
+     * @return {@code true} if a request was sent to system_server, {@code false} otherwise. Note:
+     * this does not return result of the request. For result use {@param resultReceiver} instead.
      */
     public boolean showSoftInput(View view, @ShowFlags int flags) {
         // Re-dispatch if there is a context mismatch.
@@ -2315,6 +2348,8 @@
      * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
      * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
      * {@link #RESULT_HIDDEN}.
+     * @return {@code true} if a request was sent to system_server, {@code false} otherwise. Note:
+     * this does not return result of the request. For result use {@param resultReceiver} instead.
      */
     public boolean showSoftInput(View view, @ShowFlags int flags, ResultReceiver resultReceiver) {
         return showSoftInput(view, flags, resultReceiver, SoftInputShowHideReason.SHOW_SOFT_INPUT);
@@ -2383,7 +2418,8 @@
                         flags,
                         mCurRootView.getLastClickToolType(),
                         resultReceiver,
-                        reason);
+                        reason,
+                        ASYNC_SHOW_HIDE_METHOD_ENABLED);
             }
         }
     }
@@ -2426,7 +2462,8 @@
                     flags,
                     mCurRootView.getLastClickToolType(),
                     resultReceiver,
-                    reason);
+                    reason,
+                    ASYNC_SHOW_HIDE_METHOD_ENABLED);
         }
     }
 
@@ -2459,6 +2496,9 @@
      *
      * @param windowToken The token of the window that is making the request,
      * as returned by {@link View#getWindowToken() View.getWindowToken()}.
+     * @return {@code true} if a request was sent to system_server, {@code false} otherwise. Note:
+     * this does not return result of the request. For result use {@link ResultReceiver} in
+     * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)} instead.
      */
     public boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags) {
         return hideSoftInputFromWindow(windowToken, flags, null);
@@ -2487,6 +2527,8 @@
      * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
      * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
      * {@link #RESULT_HIDDEN}.
+     * @return {@code true} if a request was sent to system_server, {@code false} otherwise. Note:
+     * this does not return result of the request. For result use {@param resultReceiver} instead.
      */
     public boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags,
             ResultReceiver resultReceiver) {
@@ -2530,7 +2572,7 @@
                 return true;
             } else {
                 return IInputMethodManagerGlobalInvoker.hideSoftInput(mClient, windowToken,
-                        statsToken, flags, resultReceiver, reason);
+                        statsToken, flags, resultReceiver, reason, ASYNC_SHOW_HIDE_METHOD_ENABLED);
             }
         }
     }
@@ -2573,7 +2615,7 @@
             ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
 
             return IInputMethodManagerGlobalInvoker.hideSoftInput(mClient, view.getWindowToken(),
-                    statsToken, flags, null, reason);
+                    statsToken, flags, null, reason, ASYNC_SHOW_HIDE_METHOD_ENABLED);
         }
     }
 
@@ -3350,7 +3392,7 @@
                         servedInputConnection == null ? null
                                 : servedInputConnection.asIRemoteAccessibilityInputConnection(),
                         view.getContext().getApplicationInfo().targetSdkVersion, targetUserId,
-                        mImeDispatcher);
+                        mImeDispatcher, ASYNC_SHOW_HIDE_METHOD_ENABLED);
             } else {
                 res = IInputMethodManagerGlobalInvoker.startInputOrWindowGainedFocus(
                         startInputReason, mClient, windowGainingFocus, startInputFlags,
@@ -3653,7 +3695,8 @@
                     statsToken,
                     HIDE_NOT_ALWAYS,
                     null,
-                    reason);
+                    reason,
+                    true /*async */);
         }
     }
 
@@ -3745,7 +3788,7 @@
 
             IInputMethodManagerGlobalInvoker.hideSoftInput(mClient, windowToken, statsToken,
                     0 /* flags */, null /* resultReceiver */,
-                    SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
+                    SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API, true /* async */);
         }
     }
 
diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig
index e294ee2..bae8aff 100644
--- a/core/java/android/view/inputmethod/flags.aconfig
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -136,3 +136,14 @@
     purpose: PURPOSE_BUGFIX
   }
 }
+
+flag {
+  name: "compatchange_for_zerojankproxy"
+  namespace: "input_method"
+  description: "Version-gate the sync/async nature of IMM#show/hideSoftInput() when using zeroJankProxy."
+  bug: "352594277"
+  is_fixed_read_only: true
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index b51678e..efbf887 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -76,10 +76,10 @@
 
     boolean showSoftInput(in IInputMethodClient client, @nullable IBinder windowToken,
             in ImeTracker.Token statsToken, int flags, int lastClickToolType,
-            in @nullable ResultReceiver resultReceiver, int reason);
+            in @nullable ResultReceiver resultReceiver, int reason, boolean async);
     boolean hideSoftInput(in IInputMethodClient client, @nullable IBinder windowToken,
             in ImeTracker.Token statsToken, int flags,
-            in @nullable ResultReceiver resultReceiver, int reason);
+            in @nullable ResultReceiver resultReceiver, int reason, boolean async);
 
     /**
      * A test API for CTS to request hiding the current soft input window, with the request origin
@@ -120,7 +120,8 @@
             in @nullable EditorInfo editorInfo, in @nullable IRemoteInputConnection inputConnection,
             in @nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
             int unverifiedTargetSdkVersion, int userId,
-            in ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq);
+            in ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq,
+            boolean useAsyncShowHideMethod);
 
     void showInputMethodPickerFromClient(in IInputMethodClient client,
             int auxiliarySubtypeMode);
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java b/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java
index 58e3452..e1f26d6 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java
@@ -116,11 +116,11 @@
         boolean showSoftInput(IInputMethodClient client, IBinder windowToken,
                 @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
                 @MotionEvent.ToolType int lastClickToolType, ResultReceiver resultReceiver,
-                @SoftInputShowHideReason int reason);
+                @SoftInputShowHideReason int reason, boolean async);
 
         boolean hideSoftInput(IInputMethodClient client, IBinder windowToken,
                 @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
-                ResultReceiver resultReceiver, @SoftInputShowHideReason int reason);
+                ResultReceiver resultReceiver, @SoftInputShowHideReason int reason, boolean async);
 
         @PermissionVerified(Manifest.permission.TEST_INPUT_METHOD)
         void hideSoftInputFromServerForTest();
@@ -132,7 +132,8 @@
                 @Nullable EditorInfo editorInfo, IRemoteInputConnection inputConnection,
                 IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
                 int unverifiedTargetSdkVersion, @UserIdInt int userId,
-                @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq);
+                @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq,
+                boolean useAsyncShowHideMethod);
 
         InputBindResult startInputOrWindowGainedFocus(
                 @StartInputReason int startInputReason, IInputMethodClient client,
@@ -290,17 +291,17 @@
     public boolean showSoftInput(IInputMethodClient client, IBinder windowToken,
             @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
             @MotionEvent.ToolType int lastClickToolType, ResultReceiver resultReceiver,
-            @SoftInputShowHideReason int reason) {
+            @SoftInputShowHideReason int reason, boolean async) {
         return mCallback.showSoftInput(client, windowToken, statsToken, flags, lastClickToolType,
-                resultReceiver, reason);
+                resultReceiver, reason, async);
     }
 
     @Override
     public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken,
             @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
-            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason, boolean async) {
         return mCallback.hideSoftInput(client, windowToken, statsToken, flags, resultReceiver,
-                reason);
+                reason, async);
     }
 
     @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD)
@@ -336,11 +337,13 @@
             IRemoteInputConnection inputConnection,
             IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
             int unverifiedTargetSdkVersion, @UserIdInt int userId,
-            @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq) {
+            @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq,
+            boolean useAsyncShowHideMethod) {
         mCallback.startInputOrWindowGainedFocusAsync(
                 startInputReason, client, windowToken, startInputFlags, softInputMode,
                 windowFlags, editorInfo, inputConnection, remoteAccessibilityInputConnection,
-                unverifiedTargetSdkVersion, userId, imeDispatcher, startInputSeq);
+                unverifiedTargetSdkVersion, userId, imeDispatcher, startInputSeq,
+                useAsyncShowHideMethod);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 2ad0d2a..7cfd2cc 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3086,7 +3086,7 @@
     public boolean showSoftInput(IInputMethodClient client, IBinder windowToken,
             @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
             int lastClickToolType, ResultReceiver resultReceiver,
-            @SoftInputShowHideReason int reason) {
+            @SoftInputShowHideReason int reason, boolean async) {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showSoftInput");
         ImeTracing.getInstance().triggerManagerServiceDump(
                 "InputMethodManagerService#showSoftInput", mDumper);
@@ -3533,7 +3533,7 @@
     @Override
     public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken,
             @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
-            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason, boolean async) {
         ImeTracing.getInstance().triggerManagerServiceDump(
                 "InputMethodManagerService#hideSoftInput", mDumper);
         synchronized (ImfLock.class) {
@@ -3675,7 +3675,8 @@
             IRemoteInputConnection inputConnection,
             IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
             int unverifiedTargetSdkVersion, @UserIdInt int userId,
-            @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq) {
+            @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq,
+            boolean useAsyncShowHideMethod) {
         // implemented by ZeroJankProxy
     }
 
diff --git a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
index c940a9c..214aa1d 100644
--- a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
+++ b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
@@ -77,6 +77,7 @@
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
 
 /**
  * A proxy that processes all {@link IInputMethodManager} calls asynchronously.
@@ -175,19 +176,45 @@
     public boolean showSoftInput(IInputMethodClient client, IBinder windowToken,
             @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
             @MotionEvent.ToolType int lastClickToolType, ResultReceiver resultReceiver,
-            @SoftInputShowHideReason int reason) {
-        offload(() -> mInner.showSoftInput(
-                client, windowToken, statsToken, flags, lastClickToolType, resultReceiver, reason));
-        return true;
+            @SoftInputShowHideReason int reason, boolean async) {
+
+        if (async) {
+            offload(() -> mInner.showSoftInput(
+                    client, windowToken, statsToken, flags, lastClickToolType, resultReceiver,
+                    reason, async));
+            return true;
+        } else {
+            final var future = CompletableFuture.supplyAsync(
+                    () -> mInner.showSoftInput(
+                            client,
+                            windowToken,
+                            statsToken,
+                            flags,
+                            lastClickToolType,
+                            resultReceiver,
+                            reason,
+                            async),
+                    this::offload);
+            return future.completeOnTimeout(false, 1, TimeUnit.SECONDS).join();
+        }
     }
 
     @Override
     public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken,
             @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
-            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
-        offload(() -> mInner.hideSoftInput(
-                client, windowToken, statsToken, flags, resultReceiver, reason));
-        return true;
+            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason, boolean async) {
+
+        if (async) {
+            offload(() -> mInner.hideSoftInput(
+                    client, windowToken, statsToken, flags, resultReceiver, reason, async));
+            return true;
+        } else {
+            final var future = CompletableFuture.supplyAsync(
+                    () -> mInner.hideSoftInput(
+                            client, windowToken, statsToken, flags, resultReceiver, reason, async),
+                    this::offload);
+            return future.completeOnTimeout(false, 1, TimeUnit.SECONDS).join();
+        }
     }
 
     @Override
@@ -207,7 +234,8 @@
             IRemoteInputConnection inputConnection,
             IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
             int unverifiedTargetSdkVersion, @UserIdInt int userId,
-            @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq) {
+            @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq,
+            boolean useAsyncShowHideMethod) {
         offload(() -> {
             InputBindResult result = mInner.startInputOrWindowGainedFocus(startInputReason, client,
                     windowToken, startInputFlags, softInputMode, windowFlags,