summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Cosmin Băieș <cosminbaies@google.com> 2025-02-07 16:18:35 +0100
committer Cosmin Băieș <cosminbaies@google.com> 2025-02-07 16:18:35 +0100
commit426cf2302443f4a8204356d5f217667989d8f89b (patch)
tree1d6cc7da2aba791072b76458da650c18a02ebde3
parent67e5e61c2a151a1c01f379816a89e31c8374310b (diff)
Switch to gesture nav in InputMethodServiceTest
Previously the tests related to (long) clicking on the IME back button and IME Switcher button were skipped if the device was not already in gesture navigation. It turns out the test is currently configured to only run on targets which are always in three button navigation, so the test is never actually ran. This uses the CTS utility to enable switching to gesture navigation mode if needed. To avoid re-creating the Activity when the mode changes, this marks that the TestActivity handles assetsPaths config changes. To avoid the countDownLatch being triggered by the IME receiving the navigation mode config change, this explicitly waits for it when necessary. Flag: EXEMPT testfix Bug: 394548201 Test: atest InputMethodServiceTest#testBackButtonClick InputMethodServiceTest#testBackButtonLongClick InputMethodServiceTest#testImeSwitchButtonClick InputMethodServiceTest#testImeSwitchButtonLongClick Change-Id: Ib8ab74918490ffa6a5d382c3dc782a3e3039970c
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java242
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml1
2 files changed, 147 insertions, 96 deletions
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index a103b0583eac..a7280c2167ea 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -31,7 +31,6 @@ import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import android.app.Instrumentation;
-import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Insets;
import android.os.RemoteException;
@@ -42,7 +41,6 @@ import android.provider.Settings;
import android.server.wm.WindowManagerStateHelper;
import android.util.Log;
import android.view.WindowManagerGlobal;
-import android.view.WindowManagerPolicyConstants;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.Flags;
import android.view.inputmethod.InputMethodManager;
@@ -59,6 +57,7 @@ import androidx.test.uiautomator.Until;
import com.android.apps.inputmethod.simpleime.ims.InputMethodServiceWrapper;
import com.android.apps.inputmethod.simpleime.testing.TestActivity;
+import com.android.compatibility.common.util.GestureNavSwitchHelper;
import com.android.compatibility.common.util.SystemUtil;
import org.junit.After;
@@ -90,6 +89,8 @@ public class InputMethodServiceTest {
private final WindowManagerStateHelper mWmState = new WindowManagerStateHelper();
+ private final GestureNavSwitchHelper mGestureNavSwitchHelper = new GestureNavSwitchHelper();
+
private final DeviceFlagsValueProvider mFlagsValueProvider = new DeviceFlagsValueProvider();
@Rule
@@ -100,7 +101,6 @@ public class InputMethodServiceTest {
private Instrumentation mInstrumentation;
private UiDevice mUiDevice;
- private Context mContext;
private InputMethodManager mImm;
private String mTargetPackageName;
private String mInputMethodId;
@@ -112,8 +112,7 @@ public class InputMethodServiceTest {
public void setUp() throws Exception {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mUiDevice = UiDevice.getInstance(mInstrumentation);
- mContext = mInstrumentation.getContext();
- mImm = mContext.getSystemService(InputMethodManager.class);
+ mImm = mInstrumentation.getContext().getSystemService(InputMethodManager.class);
mTargetPackageName = mInstrumentation.getTargetContext().getPackageName();
mInputMethodId = getInputMethodId();
prepareIme();
@@ -872,35 +871,47 @@ public class InputMethodServiceTest {
* Verifies that clicking on the IME navigation bar back button hides the IME.
*/
@Test
- public void testBackButtonClick() {
+ public void testBackButtonClick() throws Exception {
assumeTrue("Must have a navigation bar", hasNavigationBar());
- assumeTrue("Must be in gesture navigation mode", isGestureNavEnabled());
waitUntilActivityReadyForInputInjection(mActivity);
setShowImeWithHardKeyboard(true /* enabled */);
- verifyInputViewStatusOnMainSync(
- () -> {
- setDrawsImeNavBarAndSwitcherButton(true /* enabled */);
- mActivity.showImeWithWindowInsetsController();
- },
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ final boolean isGestureMode = mGestureNavSwitchHelper.isGestureMode();
- final var backButtonUiObject = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID));
- backButtonUiObject.click();
- mInstrumentation.waitForIdleSync();
+ final var restoreNav = new AutoCloseable[]{() -> {}};
+ try {
+ if (!isGestureMode) {
+ // Wait for onConfigurationChanged when changing navigation modes.
+ verifyInputViewStatus(
+ () -> restoreNav[0] = mGestureNavSwitchHelper.withGestureNavigationMode(),
+ true, /* expected */
+ false /* inputViewStarted */
+ );
+ }
- if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
- // The IME visibility is only sent at the end of the animation. Therefore, we have to
- // wait until the visibility was sent to the server and the IME window hidden.
- eventually(() -> assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse());
- } else {
- assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse();
+ verifyInputViewStatusOnMainSync(
+ () -> mActivity.showImeWithWindowInsetsController(),
+ true /* expected */,
+ true /* inputViewStarted */);
+ assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+
+ final var backButton = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID));
+ backButton.click();
+ mInstrumentation.waitForIdleSync();
+
+ if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
+ // The IME visibility is only sent at the end of the animation. Therefore, we have
+ // to wait until the visibility was sent to the server and the IME window hidden.
+ eventually(() -> assertWithMessage("IME is not shown")
+ .that(mInputMethodService.isInputViewShown()).isFalse());
+ } else {
+ assertWithMessage("IME is not shown")
+ .that(mInputMethodService.isInputViewShown()).isFalse();
+ }
+ } finally {
+ restoreNav[0].close();
}
}
@@ -908,35 +919,47 @@ public class InputMethodServiceTest {
* Verifies that long clicking on the IME navigation bar back button hides the IME.
*/
@Test
- public void testBackButtonLongClick() {
+ public void testBackButtonLongClick() throws Exception {
assumeTrue("Must have a navigation bar", hasNavigationBar());
- assumeTrue("Must be in gesture navigation mode", isGestureNavEnabled());
waitUntilActivityReadyForInputInjection(mActivity);
setShowImeWithHardKeyboard(true /* enabled */);
- verifyInputViewStatusOnMainSync(
- () -> {
- setDrawsImeNavBarAndSwitcherButton(true /* enabled */);
- mActivity.showImeWithWindowInsetsController();
- },
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ final boolean isGestureMode = mGestureNavSwitchHelper.isGestureMode();
- final var backButtonUiObject = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID));
- backButtonUiObject.longClick();
- mInstrumentation.waitForIdleSync();
+ final var restoreNav = new AutoCloseable[]{() -> {}};
+ try {
+ if (!isGestureMode) {
+ // Wait for onConfigurationChanged when changing navigation modes.
+ verifyInputViewStatus(
+ () -> restoreNav[0] = mGestureNavSwitchHelper.withGestureNavigationMode(),
+ true, /* expected */
+ false /* inputViewStarted */
+ );
+ }
- if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
- // The IME visibility is only sent at the end of the animation. Therefore, we have to
- // wait until the visibility was sent to the server and the IME window hidden.
- eventually(() -> assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse());
- } else {
- assertWithMessage("IME is not shown")
- .that(mInputMethodService.isInputViewShown()).isFalse();
+ verifyInputViewStatusOnMainSync(
+ () -> mActivity.showImeWithWindowInsetsController(),
+ true /* expected */,
+ true /* inputViewStarted */);
+ assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+
+ final var backButton = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID));
+ backButton.longClick();
+ mInstrumentation.waitForIdleSync();
+
+ if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
+ // The IME visibility is only sent at the end of the animation. Therefore, we have
+ // to wait until the visibility was sent to the server and the IME window hidden.
+ eventually(() -> assertWithMessage("IME is not shown")
+ .that(mInputMethodService.isInputViewShown()).isFalse());
+ } else {
+ assertWithMessage("IME is not shown")
+ .that(mInputMethodService.isInputViewShown()).isFalse();
+ }
+ } finally {
+ restoreNav[0].close();
}
}
@@ -945,74 +968,104 @@ public class InputMethodServiceTest {
* or switches the input method.
*/
@Test
- public void testImeSwitchButtonClick() {
+ public void testImeSwitchButtonClick() throws Exception {
assumeTrue("Must have a navigation bar", hasNavigationBar());
- assumeTrue("Must be in gesture navigation mode", isGestureNavEnabled());
waitUntilActivityReadyForInputInjection(mActivity);
setShowImeWithHardKeyboard(true /* enabled */);
- verifyInputViewStatusOnMainSync(
- () -> {
- setDrawsImeNavBarAndSwitcherButton(true /* enabled */);
- mActivity.showImeWithWindowInsetsController();
- },
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ final boolean isGestureMode = mGestureNavSwitchHelper.isGestureMode();
- final var initialInfo = mImm.getCurrentInputMethodInfo();
+ final var restoreNav = new AutoCloseable[]{() -> {}};
+ try {
+ if (!isGestureMode) {
+ // Wait for onConfigurationChanged when changing navigation modes.
+ verifyInputViewStatus(
+ () -> restoreNav[0] = mGestureNavSwitchHelper.withGestureNavigationMode(),
+ true, /* expected */
+ false /* inputViewStarted */
+ );
+ }
- final var imeSwitchButtonUiObject = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
- imeSwitchButtonUiObject.click();
- mInstrumentation.waitForIdleSync();
+ verifyInputViewStatusOnMainSync(
+ () -> {
+ setDrawsImeNavBarAndSwitcherButton(true /* enabled */);
+ mActivity.showImeWithWindowInsetsController();
+ },
+ true /* expected */,
+ true /* inputViewStarted */);
+ assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
- final var newInfo = mImm.getCurrentInputMethodInfo();
+ final var initialInfo = mImm.getCurrentInputMethodInfo();
- assertWithMessage("Input Method Switcher Menu is shown or input method was switched")
- .that(isInputMethodPickerShown(mImm) || !Objects.equals(initialInfo, newInfo))
- .isTrue();
+ final var imeSwitcherButton = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
+ imeSwitcherButton.click();
+ mInstrumentation.waitForIdleSync();
- assertWithMessage("IME is still shown after IME Switcher button was clicked")
- .that(mInputMethodService.isInputViewShown()).isTrue();
+ final var newInfo = mImm.getCurrentInputMethodInfo();
+
+ assertWithMessage("Input Method Switcher Menu is shown or input method was switched")
+ .that(isInputMethodPickerShown(mImm) || !Objects.equals(initialInfo, newInfo))
+ .isTrue();
+
+ assertWithMessage("IME is still shown after IME Switcher button was clicked")
+ .that(mInputMethodService.isInputViewShown()).isTrue();
- // Hide the IME Switcher Menu before finishing.
- mUiDevice.pressBack();
+ // Hide the IME Switcher Menu before finishing.
+ mUiDevice.pressBack();
+ } finally {
+ restoreNav[0].close();
+ }
}
/**
* Verifies that long clicking on the IME switch button shows the Input Method Switcher Menu.
*/
@Test
- public void testImeSwitchButtonLongClick() {
+ public void testImeSwitchButtonLongClick() throws Exception {
assumeTrue("Must have a navigation bar", hasNavigationBar());
- assumeTrue("Must be in gesture navigation mode", isGestureNavEnabled());
waitUntilActivityReadyForInputInjection(mActivity);
setShowImeWithHardKeyboard(true /* enabled */);
- verifyInputViewStatusOnMainSync(
- () -> {
- setDrawsImeNavBarAndSwitcherButton(true /* enabled */);
- mActivity.showImeWithWindowInsetsController();
- },
- true /* expected */,
- true /* inputViewStarted */);
- assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+ final boolean isGestureMode = mGestureNavSwitchHelper.isGestureMode();
- final var imeSwitchButtonUiObject = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
- imeSwitchButtonUiObject.longClick();
- mInstrumentation.waitForIdleSync();
+ final var restoreNav = new AutoCloseable[]{() -> {}};
+ try {
+ if (!isGestureMode) {
+ // Wait for onConfigurationChanged when changing navigation modes.
+ verifyInputViewStatus(
+ () -> restoreNav[0] = mGestureNavSwitchHelper.withGestureNavigationMode(),
+ true, /* expected */
+ false /* inputViewStarted */
+ );
+ }
- assertWithMessage("Input Method Switcher Menu is shown")
- .that(isInputMethodPickerShown(mImm)).isTrue();
- assertWithMessage("IME is still shown after IME Switcher button was long clicked")
- .that(mInputMethodService.isInputViewShown()).isTrue();
+ verifyInputViewStatusOnMainSync(
+ () -> {
+ setDrawsImeNavBarAndSwitcherButton(true /* enabled */);
+ mActivity.showImeWithWindowInsetsController();
+ },
+ true /* expected */,
+ true /* inputViewStarted */);
+ assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();
+
+ final var imeSwitcherButton = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
+ imeSwitcherButton.longClick();
+ mInstrumentation.waitForIdleSync();
- // Hide the IME Switcher Menu before finishing.
- mUiDevice.pressBack();
+ assertWithMessage("Input Method Switcher Menu is shown")
+ .that(isInputMethodPickerShown(mImm)).isTrue();
+ assertWithMessage("IME is still shown after IME Switcher button was long clicked")
+ .that(mInputMethodService.isInputViewShown()).isTrue();
+
+ // Hide the IME Switcher Menu before finishing.
+ mUiDevice.pressBack();
+ } finally {
+ restoreNav[0].close();
+ }
}
private void verifyInputViewStatus(@NonNull Runnable runnable, boolean expected,
@@ -1105,6 +1158,9 @@ public class InputMethodServiceTest {
// Get the new TestActivity.
mActivity = TestActivity.getLastCreatedInstance();
assertWithMessage("Re-created activity is not null").that(mActivity).isNotNull();
+ // Wait for the new EditText to be served by InputMethodManager.
+ eventually(() -> assertWithMessage("Has an input connection to the re-created Activity")
+ .that(mImm.hasActiveInputConnection(mActivity.getEditText())).isTrue());
}
verifyInputViewStatusOnMainSync(
@@ -1214,18 +1270,12 @@ public class InputMethodServiceTest {
return uiObject;
}
- /** Checks whether gesture navigation move is enabled. */
- private boolean isGestureNavEnabled() {
- return mContext.getResources().getInteger(
- com.android.internal.R.integer.config_navBarInteractionMode)
- == WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
- }
-
/** Checks whether the device has a navigation bar on the IME's display. */
private boolean hasNavigationBar() {
try {
return WindowManagerGlobal.getWindowManagerService()
- .hasNavigationBar(mInputMethodService.getDisplayId());
+ .hasNavigationBar(mInputMethodService.getDisplayId())
+ && mGestureNavSwitchHelper.hasNavigationBar();
} catch (RemoteException e) {
fail("Failed to check whether the device has a navigation bar: " + e.getMessage());
return false;
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml
index cf7d660a68ef..00873de4aaed 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml
@@ -42,6 +42,7 @@
<activity android:name="com.android.apps.inputmethod.simpleime.testing.TestActivity"
android:exported="false"
android:label="TestActivity"
+ android:configChanges="assetsPaths"
android:launchMode="singleInstance"
android:excludeFromRecents="true"
android:noHistory="true"