Loading services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +25 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeTargetWindowState; import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeVisibilityResult; import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME; import static com.android.server.inputmethod.InputMethodBindingController.TIME_TO_RECONNECT; import static com.android.server.inputmethod.InputMethodUtils.isSoftInputModeStateVisibleAllowed; Loading Loading @@ -2367,6 +2368,28 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } /** * Called when {@link #resetCurrentMethodAndClientLocked(int)} invoked for clean-up states * before unbinding the current method. */ @GuardedBy("ImfLock.class") void onUnbindCurrentMethodByReset() { final ImeTargetWindowState winState = mVisibilityStateComputer.getWindowStateOrNull( mCurFocusedWindow); if (winState != null && !winState.isRequestedImeVisible() && !mVisibilityStateComputer.isInputShown()) { // Normally, the focus window will apply the IME visibility state to // WindowManager when the IME has applied it. But it would be too late when // switching IMEs in between different users. (Since the focused IME will // first unbind the service to switch to bind the next user of the IME // service, that wouldn't make the attached IME token validity check in time) // As a result, we have to notify WM to apply IME visibility before clearing the // binding states in the first place. mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, mCurStatsToken, STATE_HIDE_IME); } } /** {@code true} when a {@link ClientState} has attached from starting the input connection. */ @GuardedBy("ImfLock.class") boolean hasAttachedClient() { Loading Loading @@ -2838,6 +2861,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("ImfLock.class") void resetCurrentMethodAndClientLocked(@UnbindReason int unbindClientReason) { setSelectedMethodIdLocked(null); // Callback before clean-up binding states. onUnbindCurrentMethodByReset(); mBindingController.unbindCurrentMethod(); unbindCurrentClientLocked(unbindClientReason); } Loading services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java +25 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.inputmethodservice.InputMethodService.IME_ACTIVE; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE; import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_SOFT_INPUT; import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_SWITCH_USER; import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_SOFT_INPUT; import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME; import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT; Loading @@ -43,6 +44,7 @@ import android.view.inputmethod.InputMethodManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.internal.inputmethod.InputBindResult; import com.android.internal.inputmethod.StartInputFlags; import com.android.internal.inputmethod.StartInputReason; Loading Loading @@ -165,6 +167,29 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe verify(mMockImeTargetVisibilityPolicy).removeImeScreenshot(eq(Display.DEFAULT_DISPLAY)); } @Test public void testApplyImeVisibility_hideImeWhenUnbinding() { mInputMethodManagerService.setAttachedClientForTesting(null); startInputOrWindowGainedFocus(mWindowToken, SOFT_INPUT_STATE_ALWAYS_VISIBLE); ExtendedMockito.spyOn(mVisibilityApplier); synchronized (ImfLock.class) { // Simulate the system hides the IME when switching IME services in different users. // (e.g. unbinding the IME from the current user to the profile user) final int displayIdToShowIme = mInputMethodManagerService.getDisplayIdToShowImeLocked(); mInputMethodManagerService.hideCurrentInputLocked(mWindowToken, null, 0, null, HIDE_SWITCH_USER); mInputMethodManagerService.onUnbindCurrentMethodByReset(); // Expects applyImeVisibility() -> hideIme() will be called to notify WM for syncing // the IME hidden state. verify(mVisibilityApplier).applyImeVisibility(eq(mWindowToken), any(), eq(STATE_HIDE_IME)); verify(mInputMethodManagerService.mWindowManagerInternal).hideIme( eq(mWindowToken), eq(displayIdToShowIme), eq(null)); } } private InputBindResult startInputOrWindowGainedFocus(IBinder windowToken, int softInputMode) { return mInputMethodManagerService.startInputOrWindowGainedFocus( StartInputReason.WINDOW_FOCUS_GAIN /* startInputReason */, Loading Loading
services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +25 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeTargetWindowState; import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeVisibilityResult; import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME; import static com.android.server.inputmethod.InputMethodBindingController.TIME_TO_RECONNECT; import static com.android.server.inputmethod.InputMethodUtils.isSoftInputModeStateVisibleAllowed; Loading Loading @@ -2367,6 +2368,28 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } /** * Called when {@link #resetCurrentMethodAndClientLocked(int)} invoked for clean-up states * before unbinding the current method. */ @GuardedBy("ImfLock.class") void onUnbindCurrentMethodByReset() { final ImeTargetWindowState winState = mVisibilityStateComputer.getWindowStateOrNull( mCurFocusedWindow); if (winState != null && !winState.isRequestedImeVisible() && !mVisibilityStateComputer.isInputShown()) { // Normally, the focus window will apply the IME visibility state to // WindowManager when the IME has applied it. But it would be too late when // switching IMEs in between different users. (Since the focused IME will // first unbind the service to switch to bind the next user of the IME // service, that wouldn't make the attached IME token validity check in time) // As a result, we have to notify WM to apply IME visibility before clearing the // binding states in the first place. mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, mCurStatsToken, STATE_HIDE_IME); } } /** {@code true} when a {@link ClientState} has attached from starting the input connection. */ @GuardedBy("ImfLock.class") boolean hasAttachedClient() { Loading Loading @@ -2838,6 +2861,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("ImfLock.class") void resetCurrentMethodAndClientLocked(@UnbindReason int unbindClientReason) { setSelectedMethodIdLocked(null); // Callback before clean-up binding states. onUnbindCurrentMethodByReset(); mBindingController.unbindCurrentMethod(); unbindCurrentClientLocked(unbindClientReason); } Loading
services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java +25 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.inputmethodservice.InputMethodService.IME_ACTIVE; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE; import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_SOFT_INPUT; import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_SWITCH_USER; import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_SOFT_INPUT; import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME; import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT; Loading @@ -43,6 +44,7 @@ import android.view.inputmethod.InputMethodManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.internal.inputmethod.InputBindResult; import com.android.internal.inputmethod.StartInputFlags; import com.android.internal.inputmethod.StartInputReason; Loading Loading @@ -165,6 +167,29 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe verify(mMockImeTargetVisibilityPolicy).removeImeScreenshot(eq(Display.DEFAULT_DISPLAY)); } @Test public void testApplyImeVisibility_hideImeWhenUnbinding() { mInputMethodManagerService.setAttachedClientForTesting(null); startInputOrWindowGainedFocus(mWindowToken, SOFT_INPUT_STATE_ALWAYS_VISIBLE); ExtendedMockito.spyOn(mVisibilityApplier); synchronized (ImfLock.class) { // Simulate the system hides the IME when switching IME services in different users. // (e.g. unbinding the IME from the current user to the profile user) final int displayIdToShowIme = mInputMethodManagerService.getDisplayIdToShowImeLocked(); mInputMethodManagerService.hideCurrentInputLocked(mWindowToken, null, 0, null, HIDE_SWITCH_USER); mInputMethodManagerService.onUnbindCurrentMethodByReset(); // Expects applyImeVisibility() -> hideIme() will be called to notify WM for syncing // the IME hidden state. verify(mVisibilityApplier).applyImeVisibility(eq(mWindowToken), any(), eq(STATE_HIDE_IME)); verify(mInputMethodManagerService.mWindowManagerInternal).hideIme( eq(mWindowToken), eq(displayIdToShowIme), eq(null)); } } private InputBindResult startInputOrWindowGainedFocus(IBinder windowToken, int softInputMode) { return mInputMethodManagerService.startInputOrWindowGainedFocus( StartInputReason.WINDOW_FOCUS_GAIN /* startInputReason */, Loading