Loading services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java +4 −5 Original line number Diff line number Diff line Loading @@ -136,17 +136,16 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier { mWindowManagerInternal.showImePostLayout(windowToken, statsToken); break; case STATE_HIDE_IME: if (mService.mCurFocusedWindowClient != null) { if (mService.hasAttachedClient()) { ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY); // IMMS only knows of focused window, not the actual IME target. // e.g. it isn't aware of any window that has both // NOT_FOCUSABLE, ALT_FOCUSABLE_IM flags set and can the IME target. // Send it to window manager to hide IME from IME target window. // TODO(b/139861270): send to mCurClient.client once IMMS is aware of // actual IME target. // Send it to window manager to hide IME from the actual IME control target // of the target display. mWindowManagerInternal.hideIme(windowToken, mService.mCurFocusedWindowClient.mSelfReportedDisplayId, statsToken); mService.getDisplayIdToShowImeLocked(), statsToken); } else { ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY); Loading services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +13 −0 Original line number Diff line number Diff line Loading @@ -2339,6 +2339,19 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } /** {@code true} when a {@link ClientState} has attached from starting the input connection. */ @GuardedBy("ImfLock.class") boolean hasAttachedClient() { return mCurClient != null; } @VisibleForTesting void setAttachedClientForTesting(@NonNull ClientState cs) { synchronized (ImfLock.class) { mCurClient = cs; } } @GuardedBy("ImfLock.class") void clearInputShownLocked() { mVisibilityStateComputer.setInputShown(false); Loading services/core/java/com/android/server/wm/WindowManagerInternal.java +2 −2 Original line number Diff line number Diff line Loading @@ -740,7 +740,7 @@ public abstract class WindowManagerInternal { /** * Show IME on imeTargetWindow once IME has finished layout. * * @param imeTargetWindowToken token of the (IME target) window on which IME should be shown. * @param imeTargetWindowToken token of the (IME target) window which IME should be shown. * @param statsToken the token tracking the current IME show request or {@code null} otherwise. */ public abstract void showImePostLayout(IBinder imeTargetWindowToken, Loading @@ -749,7 +749,7 @@ public abstract class WindowManagerInternal { /** * Hide IME using imeTargetWindow when requested. * * @param imeTargetWindowToken token of the (IME target) window on which IME should be hidden. * @param imeTargetWindowToken token of the (IME target) window on which requests hiding IME. * @param displayId the id of the display the IME is on. * @param statsToken the token tracking the current IME hide request or {@code null} otherwise. */ Loading services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java +42 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.inputmethod; 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.SHOW_SOFT_INPUT; Loading @@ -35,11 +36,16 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.view.inputmethod.InputMethodManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.internal.inputmethod.InputBindResult; import com.android.internal.inputmethod.StartInputFlags; import com.android.internal.inputmethod.StartInputReason; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -60,8 +66,8 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe super.setUp(); mVisibilityApplier = (DefaultImeVisibilityApplier) mInputMethodManagerService.getVisibilityApplier(); mInputMethodManagerService.mCurFocusedWindowClient = mock( InputMethodManagerService.ClientState.class); mInputMethodManagerService.setAttachedClientForTesting( mock(InputMethodManagerService.ClientState.class)); } @Test Loading Loading @@ -119,4 +125,38 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_SHOW_IME_IMPLICIT); verifyShowSoftInput(true, true, InputMethodManager.SHOW_IMPLICIT); } @Test public void testApplyImeVisibility_hideImeFromTargetOnSecondaryDisplay() { // Init a IME target client on the secondary display to show IME. mInputMethodManagerService.addClient(mMockInputMethodClient, mMockRemoteInputConnection, 10 /* selfReportedDisplayId */); mInputMethodManagerService.setAttachedClientForTesting(null); startInputOrWindowGainedFocus(mWindowToken, SOFT_INPUT_STATE_ALWAYS_VISIBLE); synchronized (ImfLock.class) { final int displayIdToShowIme = mInputMethodManagerService.getDisplayIdToShowImeLocked(); // Verify hideIme will apply the expected displayId when the default IME // visibility applier app STATE_HIDE_IME. mVisibilityApplier.applyImeVisibility(mWindowToken, null, 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 */, mMockInputMethodClient /* client */, windowToken /* windowToken */, StartInputFlags.VIEW_HAS_FOCUS | StartInputFlags.IS_TEXT_EDITOR, softInputMode /* softInputMode */, 0 /* windowFlags */, mEditorInfo /* editorInfo */, mMockRemoteInputConnection /* inputConnection */, mMockRemoteAccessibilityInputConnection /* remoteAccessibilityInputConnection */, mTargetSdkVersion /* unverifiedTargetSdkVersion */, mCallingUserId /* userId */, mMockImeOnBackInvokedDispatcher /* imeDispatcher */); } } Loading
services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java +4 −5 Original line number Diff line number Diff line Loading @@ -136,17 +136,16 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier { mWindowManagerInternal.showImePostLayout(windowToken, statsToken); break; case STATE_HIDE_IME: if (mService.mCurFocusedWindowClient != null) { if (mService.hasAttachedClient()) { ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY); // IMMS only knows of focused window, not the actual IME target. // e.g. it isn't aware of any window that has both // NOT_FOCUSABLE, ALT_FOCUSABLE_IM flags set and can the IME target. // Send it to window manager to hide IME from IME target window. // TODO(b/139861270): send to mCurClient.client once IMMS is aware of // actual IME target. // Send it to window manager to hide IME from the actual IME control target // of the target display. mWindowManagerInternal.hideIme(windowToken, mService.mCurFocusedWindowClient.mSelfReportedDisplayId, statsToken); mService.getDisplayIdToShowImeLocked(), statsToken); } else { ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY); Loading
services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +13 −0 Original line number Diff line number Diff line Loading @@ -2339,6 +2339,19 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } /** {@code true} when a {@link ClientState} has attached from starting the input connection. */ @GuardedBy("ImfLock.class") boolean hasAttachedClient() { return mCurClient != null; } @VisibleForTesting void setAttachedClientForTesting(@NonNull ClientState cs) { synchronized (ImfLock.class) { mCurClient = cs; } } @GuardedBy("ImfLock.class") void clearInputShownLocked() { mVisibilityStateComputer.setInputShown(false); Loading
services/core/java/com/android/server/wm/WindowManagerInternal.java +2 −2 Original line number Diff line number Diff line Loading @@ -740,7 +740,7 @@ public abstract class WindowManagerInternal { /** * Show IME on imeTargetWindow once IME has finished layout. * * @param imeTargetWindowToken token of the (IME target) window on which IME should be shown. * @param imeTargetWindowToken token of the (IME target) window which IME should be shown. * @param statsToken the token tracking the current IME show request or {@code null} otherwise. */ public abstract void showImePostLayout(IBinder imeTargetWindowToken, Loading @@ -749,7 +749,7 @@ public abstract class WindowManagerInternal { /** * Hide IME using imeTargetWindow when requested. * * @param imeTargetWindowToken token of the (IME target) window on which IME should be hidden. * @param imeTargetWindowToken token of the (IME target) window on which requests hiding IME. * @param displayId the id of the display the IME is on. * @param statsToken the token tracking the current IME hide request or {@code null} otherwise. */ Loading
services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java +42 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.inputmethod; 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.SHOW_SOFT_INPUT; Loading @@ -35,11 +36,16 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.view.inputmethod.InputMethodManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.internal.inputmethod.InputBindResult; import com.android.internal.inputmethod.StartInputFlags; import com.android.internal.inputmethod.StartInputReason; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -60,8 +66,8 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe super.setUp(); mVisibilityApplier = (DefaultImeVisibilityApplier) mInputMethodManagerService.getVisibilityApplier(); mInputMethodManagerService.mCurFocusedWindowClient = mock( InputMethodManagerService.ClientState.class); mInputMethodManagerService.setAttachedClientForTesting( mock(InputMethodManagerService.ClientState.class)); } @Test Loading Loading @@ -119,4 +125,38 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_SHOW_IME_IMPLICIT); verifyShowSoftInput(true, true, InputMethodManager.SHOW_IMPLICIT); } @Test public void testApplyImeVisibility_hideImeFromTargetOnSecondaryDisplay() { // Init a IME target client on the secondary display to show IME. mInputMethodManagerService.addClient(mMockInputMethodClient, mMockRemoteInputConnection, 10 /* selfReportedDisplayId */); mInputMethodManagerService.setAttachedClientForTesting(null); startInputOrWindowGainedFocus(mWindowToken, SOFT_INPUT_STATE_ALWAYS_VISIBLE); synchronized (ImfLock.class) { final int displayIdToShowIme = mInputMethodManagerService.getDisplayIdToShowImeLocked(); // Verify hideIme will apply the expected displayId when the default IME // visibility applier app STATE_HIDE_IME. mVisibilityApplier.applyImeVisibility(mWindowToken, null, 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 */, mMockInputMethodClient /* client */, windowToken /* windowToken */, StartInputFlags.VIEW_HAS_FOCUS | StartInputFlags.IS_TEXT_EDITOR, softInputMode /* softInputMode */, 0 /* windowFlags */, mEditorInfo /* editorInfo */, mMockRemoteInputConnection /* inputConnection */, mMockRemoteAccessibilityInputConnection /* remoteAccessibilityInputConnection */, mTargetSdkVersion /* unverifiedTargetSdkVersion */, mCallingUserId /* userId */, mMockImeOnBackInvokedDispatcher /* imeDispatcher */); } }