From 31e467846378c12ca51c92cc4cc35e59d495288d Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Sat, 3 Sep 2022 00:00:39 +0800 Subject: [PATCH 1/4] Add InputMethodManagerDelegate#getLockObject As CL[1] introduces per-window based ImeFocusController for handling the IME served view focus update logic. However, for InputMethodManager APIs requires to access ImeFocusController#{mServedView, mNextServedView} for starting the input connection or checking the caller's validity, which needs a lock for thread safety. As a result, it would make sense to expose mH for ImeFocusController through an new method InputMethodManagerDelegate#getLockObject to protect the data consistancy during InputMethodMananger APIs invoking to access the served view. Also, renaming the methods (and update the javadoc) with "Locked" sufix: - ImeFocusController#get{Served, NextServed}View - ImeFocusController#set{Served, NextServed}View Note that this is a refactoring preperation CL with added a TODO that will use getLockObject in the follow-up CL. [1]: Ib455704fe1e9d243f93190a84f230210dbceac2a Bug: 244504062 Test: atest CtsInputMethodTestCases Change-Id: I9c072b829d1db1e68b65e766d764ee71cb16e6a2 --- .../java/android/view/ImeFocusController.java | 44 +++++++++++++++++-- .../view/inputmethod/BaseInputConnection.java | 5 +-- .../view/inputmethod/InputMethodManager.java | 36 ++++++++++++--- 3 files changed, 72 insertions(+), 13 deletions(-) diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java index a5ac9480d2cfa..89e901cd70fe9 100644 --- a/core/java/android/view/ImeFocusController.java +++ b/core/java/android/view/ImeFocusController.java @@ -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 @@ -284,21 +297,44 @@ public final class ImeFocusController { 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. + * + * TODO(b/244504062): Use this to all places requires synchronization in controller. + */ + 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) { + // TODO(b/244504062): Remove this method dependency from InputMethodManager. + public void setServedViewLocked(View view) { mServedView = view; } - public void setNextServedView(View view) { + // TODO(b/244504062): Remove this method dependency from InputMethodManager. + public void setNextServedViewLocked(View view) { mNextServedView = view; } diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index 624937ff1d990..f0025922e1986 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -838,11 +838,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() diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 0c7c1639e6c73..84239385775ca 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -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. @@ -786,7 +801,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 && hasActiveConnection(focusedView); if (DEBUG) { @@ -878,6 +893,16 @@ public final class InputMethodManager { && mServedInputConnection.getServedView() == 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 */ @@ -898,26 +923,27 @@ 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); + mCurRootView.getImeFocusController().setServedViewLocked(view); } } @GuardedBy("mH") private void setNextServedViewLocked(View view) { if (mCurRootView != null) { - mCurRootView.getImeFocusController().setNextServedView(view); + mCurRootView.getImeFocusController().setNextServedViewLocked(view); } } From 6924863b3794f55f555d8bd9907af4b82ee2bc54 Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Sat, 3 Sep 2022 00:52:04 +0800 Subject: [PATCH 2/4] Remove ImeFocusController#set{Served, NextServed}View As ImeFocusController#set{Served, NextServed}View originally exposes to InputMethodManager is only for clearing the served view in IMM#finishInputLocked() with a special code logic: ``` setNextServedView(null); if (getServedView() != null) { // do finish input setServedView(null); } ``` which isn't necessary and can be clean-up with a method to notify ImeFocusController to clear the served / next served view, then doing the rest of finshing logic when the method has cleared the served view: ``` if (controller.clearServedViewsLocked() != null) { // do finish input } ``` With this change, we can simply remove the set{Served, NextServed}View to get rid of this dependency with InputMethodManager. Bug: 244504062 Test: atest CtsInputMethodTestCases Change-Id: Ibcde35765c0e2e6c372aa64dbc7e774a8d860543 --- .../java/android/view/ImeFocusController.java | 25 +++++++++++++------ .../view/inputmethod/InputMethodManager.java | 22 +++------------- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java index 89e901cd70fe9..2d2b0f5369d15 100644 --- a/core/java/android/view/ImeFocusController.java +++ b/core/java/android/view/ImeFocusController.java @@ -328,14 +328,23 @@ public final class ImeFocusController { return mNextServedView; } - // TODO(b/244504062): Remove this method dependency from InputMethodManager. - public void setServedViewLocked(View view) { - mServedView = view; - } - - // TODO(b/244504062): Remove this method dependency from InputMethodManager. - public void setNextServedViewLocked(View view) { - mNextServedView = 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; + } + return clearedView; } /** diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 84239385775ca..b18ca86ff3667 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -933,20 +933,6 @@ public final class InputMethodManager { : null; } - @GuardedBy("mH") - private void setServedViewLocked(View view) { - if (mCurRootView != null) { - mCurRootView.getImeFocusController().setServedViewLocked(view); - } - } - - @GuardedBy("mH") - private void setNextServedViewLocked(View view) { - if (mCurRootView != null) { - mCurRootView.getImeFocusController().setNextServedViewLocked(view); - } - } - private ImeFocusController getFocusController() { synchronized (mH) { if (mCurRootView != null) { @@ -1793,13 +1779,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(); From ea0c2ee27023aaec4c4ac827b65e75e858f81b5c Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Sat, 3 Sep 2022 01:31:25 +0800 Subject: [PATCH 3/4] Use getLockObject to sync ImeFocusController#{mServedView, mNextServedView} As CL[1] added InputMethodManagerDelegate#getLockObject that used for protecting mServedView/mNextServedView in ImeFocusController when we exposed getServedView/getNextServedView for InputMethodManager to access with thread safty. Add synchornize block for all places that accessing {mServedView, mNextServedView} in ImeFocusController. [1]: I9c072b829d1db1e68b65e766d764ee71cb16e6a2 Bug: 244504062 Test: atest CtsInputMethodTestCases Change-Id: I8357bfafeaf0a40e3b74eec2fc59a47309451f18 --- .../java/android/view/ImeFocusController.java | 155 +++++++++++------- 1 file changed, 94 insertions(+), 61 deletions(-) diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java index 2d2b0f5369d15..f4daec121fc60 100644 --- a/core/java/android/view/ImeFocusController.java +++ b/core/java/android/view/ImeFocusController.java @@ -136,45 +136,58 @@ 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()) { + // TODO(b/244504062): Remove isRestartOnNextWindowFocus. + if (immDelegate.isRestartOnNextWindowFocus(true /* reset */)) { + if (DEBUG) Log.v(TAG, "Restarting due to isRestartOnNextWindowFocus as true"); + forceFocus = true; + } - // Update mNextServedView when focusedView changed. - onViewFocusChanged(viewForWindowFocus, true); + // 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; + // 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, 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)) { - return false; + 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() + : "")); + } + // Close the connection when no next served view coming. + if (mNextServedView == null) { + immDelegate.finishInput(); + immDelegate.closeCurrentIme(); + return false; + } + mServedView = mNextServedView; + immDelegate.finishComposingText(); } - if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView - + " next=" + mNextServedView - + " force=" + forceNewFocus - + " package=" - + (mServedView != null ? mServedView.getContext().getPackageName() : "")); - - // 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 */, @@ -188,51 +201,61 @@ public final class ImeFocusController { if (view == null || view.isTemporarilyDetached()) { return; } - if (!getImmDelegate().isCurrentRootView(view.getViewRootImpl())) { - return; - } - if (!view.hasImeFocus() || !view.hasWindowFocus()) { - return; - } - if (DEBUG) Log.d(TAG, "onViewFocusChanged, view=" + InputMethodDebug.dumpViewInfo(view) - + ", mServedView=" + InputMethodDebug.dumpViewInfo(mServedView)); + 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; + // 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(); } @UiThread void onViewDetachedFromWindow(View view) { - if (!getImmDelegate().isCurrentRootView(view.getViewRootImpl())) { - return; - } - if (mNextServedView == view) { - mNextServedView = null; - } - if (mServedView == view) { - mViewRootImpl.dispatchCheckFocus(); + final InputMethodManagerDelegate immDelegate = getImmDelegate(); + synchronized (immDelegate.getLockObject()) { + if (!immDelegate.isCurrentRootView(view.getViewRootImpl())) { + return; + } + if (mNextServedView == view) { + mNextServedView = null; + } + if (mServedView == view) { + mViewRootImpl.dispatchCheckFocus(); + } } } @UiThread void onWindowDismissed() { final InputMethodManagerDelegate immDelegate = getImmDelegate(); - if (!immDelegate.isCurrentRootView(mViewRootImpl)) { - return; + synchronized (immDelegate.getLockObject()) { + if (!immDelegate.isCurrentRootView(mViewRootImpl)) { + return; + } + if (mServedView != null) { + immDelegate.finishInput(); + } + immDelegate.setCurrentRootView(null); } - if (mServedView != null) { - immDelegate.finishInput(); - } - immDelegate.setCurrentRootView(null); mHasImeFocus = false; } @@ -283,9 +306,21 @@ 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); + /** + * 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 startInputAsyncOnWindowFocusGain(View rootView, @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus); @@ -302,8 +337,6 @@ public final class ImeFocusController { * Returns the {@code InputMethodManager#mH} lock object. * Used for {@link ImeFocusController} to guard the served view being accessed by * {@link InputMethodManager} in different threads. - * - * TODO(b/244504062): Use this to all places requires synchronization in controller. */ Object getLockObject(); } From 786f31f2289920a30dec1912700c0e98cfa51725 Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Sun, 18 Sep 2022 16:02:31 +0800 Subject: [PATCH 4/4] Remove InputMethodManagerDelegate#isRestartOnNextWindowFocus As isRestartOnNextWindowFocus is to check InputMethodManager#mRestartOnNextWindowFocus flag if the input connection is needed to force re-start when calling startInputAsyncOnWindowFocusGain during gaining the window focus from ImeFocusController#onPostWindowFocus next time. (e.g. Switching IME apps from IME picker dialog) Since in startInputOnWindowAyncFocusGain can just check mRestartOnNextWindowFocus directly without exposing isRestartOnNextWindowFocus, we could just simplied with inlining the check logic. Also, noticed in startInputAsyncOnWindowFocusGain has already reverted CL[1]'s asynchronize starting input logic for some reasons, as a result, renaming to startInputOnWindowFocusGain in case misleading. [1]: I6aa4a664cfd0c86f75cee2457715317194bbe5e2 Bug: 244504062 Test: atest CtsInputMethodTestCases Change-Id: I9335262136950021efb7b4b73c7eeb930e1333bb --- .../java/android/view/ImeFocusController.java | 11 ++------ .../view/inputmethod/InputMethodManager.java | 27 ++++++++----------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java index f4daec121fc60..d4875d400c5b7 100644 --- a/core/java/android/view/ImeFocusController.java +++ b/core/java/android/view/ImeFocusController.java @@ -137,12 +137,6 @@ public final class ImeFocusController { boolean forceFocus = false; final InputMethodManagerDelegate immDelegate = getImmDelegate(); synchronized (immDelegate.getLockObject()) { - // TODO(b/244504062): Remove isRestartOnNextWindowFocus. - if (immDelegate.isRestartOnNextWindowFocus(true /* reset */)) { - if (DEBUG) Log.v(TAG, "Restarting due to isRestartOnNextWindowFocus as true"); - forceFocus = true; - } - // Update mNextServedView when focusedView changed. onViewFocusChanged(viewForWindowFocus, true); @@ -155,7 +149,7 @@ public final class ImeFocusController { } } - immDelegate.startInputAsyncOnWindowFocusGain(viewForWindowFocus, + immDelegate.startInputOnWindowFocusGain(viewForWindowFocus, windowAttribute.softInputMode, windowAttribute.flags, forceFocus); } @@ -321,7 +315,7 @@ public final class ImeFocusController { * {@link InputMethodManagerDelegate#getLockObject()} while {@link InputMethodManager} * calling into app-code in different threads. */ - void startInputAsyncOnWindowFocusGain(View rootView, + void startInputOnWindowFocusGain(View rootView, @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus); void finishInput(); @@ -330,7 +324,6 @@ public final class ImeFocusController { void finishComposingText(); void setCurrentRootView(ViewRootImpl rootView); boolean isCurrentRootView(ViewRootImpl rootView); - boolean isRestartOnNextWindowFocus(boolean reset); boolean hasActiveConnection(View view); /** diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index b18ca86ff3667..7764526ae30df 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -771,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; @@ -787,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 @@ -859,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. *