diff options
| author | 2019-10-29 15:27:16 -0700 | |
|---|---|---|
| committer | 2019-10-31 10:12:34 -0700 | |
| commit | e0172102b9c9a9640209e3223bb6c60fe1d5cabb (patch) | |
| tree | 39c06160b1b7e2d857c9e8750699eb96272d9c60 | |
| parent | 4a0b1750ef697bb4f329a3beffe88bf46e1e6385 (diff) | |
Move startInput for WINDOW_FOCUS_GAIN to background thread
For a typical window with Editor, IMM#startInputOrWindowGainedFocus
is called twice: first for WINDOW_FOCUS_GAIN (dummyInput), then
CHECK_FOCUS when actual editor receives focus and startsInput.
The first once can be moved to background thread and second startInput
will wait till its finished.
Bug: 139806621
Test: Manually launch activities with editors and confirm no change in
behavior.
Change-Id: I6aa4a664cfd0c86f75cee2457715317194bbe5e2
| -rw-r--r-- | core/java/android/view/inputmethod/InputMethodManager.java | 77 |
1 files changed, 55 insertions, 22 deletions
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 6420d71216cd..58915320c695 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -92,7 +92,10 @@ import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; /** @@ -422,6 +425,13 @@ public final class InputMethodManager { int mCursorCandEnd; /** + * Initial startInput with {@link StartInputReason.WINDOW_FOCUS_GAIN} is executed + * in a background thread. Later, if there is an actual startInput it will wait on + * main thread till the background thread completes. + */ + private CompletableFuture<Void> mWindowFocusGainFuture; + + /** * The instance that has previously been sent to the input method. */ private CursorAnchorInfo mCursorAnchorInfo = null; @@ -1598,6 +1608,18 @@ public final class InputMethodManager { boolean startInputInner(@StartInputReason int startInputReason, @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, int windowFlags) { + if (startInputReason != StartInputReason.WINDOW_FOCUS_GAIN + && mWindowFocusGainFuture != null) { + try { + mWindowFocusGainFuture.get(); + } catch (ExecutionException | InterruptedException e) { + // do nothing + } catch (CancellationException e) { + // window no longer has focus. + return true; + } + } + final View view; synchronized (mH) { view = mServedView; @@ -1951,31 +1973,38 @@ public final class InputMethodManager { startInputFlags |= StartInputFlags.FIRST_WINDOW_FOCUS_GAIN; } - if (checkFocusNoStartInput(forceNewFocus)) { - // We need to restart input on the current focus view. This - // should be done in conjunction with telling the system service - // about the window gaining focus, to help make the transition - // smooth. - if (startInputInner(StartInputReason.WINDOW_FOCUS_GAIN, rootView.getWindowToken(), - startInputFlags, softInputMode, windowFlags)) { - return; - } + final boolean forceNewFocus1 = forceNewFocus; + final int startInputFlags1 = startInputFlags; + if (mWindowFocusGainFuture != null) { + mWindowFocusGainFuture.cancel(false/* mayInterruptIfRunning */); } + mWindowFocusGainFuture = CompletableFuture.runAsync(() -> { + if (checkFocusNoStartInput(forceNewFocus1)) { + // We need to restart input on the current focus view. This + // should be done in conjunction with telling the system service + // about the window gaining focus, to help make the transition + // smooth. + if (startInputInner(StartInputReason.WINDOW_FOCUS_GAIN, rootView.getWindowToken(), + startInputFlags1, softInputMode, windowFlags)) { + return; + } + } - // For some reason we didn't do a startInput + windowFocusGain, so - // we'll just do a window focus gain and call it a day. - synchronized (mH) { - try { - if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput"); - mService.startInputOrWindowGainedFocus( - StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient, - rootView.getWindowToken(), startInputFlags, softInputMode, windowFlags, - null, null, 0 /* missingMethodFlags */, - rootView.getContext().getApplicationInfo().targetSdkVersion); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + // For some reason we didn't do a startInput + windowFocusGain, so + // we'll just do a window focus gain and call it a day. + synchronized (mH) { + try { + if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput"); + mService.startInputOrWindowGainedFocus( + StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient, + rootView.getWindowToken(), startInputFlags1, softInputMode, windowFlags, + null, null, 0 /* missingMethodFlags */, + rootView.getContext().getApplicationInfo().targetSdkVersion); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } - } + }); } /** @hide */ @@ -1990,6 +2019,10 @@ public final class InputMethodManager { // If the mCurRootView is losing window focus, release the strong reference to it // so as not to prevent it from being garbage-collected. mCurRootView = null; + if (mWindowFocusGainFuture != null) { + mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */); + mWindowFocusGainFuture = null; + } } else { if (DEBUG) { Log.v(TAG, "Ignoring onPreWindowFocus()." |