Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 426cf230 authored by Cosmin Băieș's avatar Cosmin Băieș
Browse files

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
parent 67e5e61c
Loading
Loading
Loading
Loading
+146 −96
Original line number Diff line number Diff line
@@ -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,72 +871,96 @@ 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 */);

        final boolean isGestureMode = mGestureNavSwitchHelper.isGestureMode();

        final var restoreNav = new AutoCloseable[]{() -> {}};
        try {
            if (!isGestureMode) {
                //  Wait for onConfigurationChanged when changing navigation modes.
                verifyInputViewStatus(
                        () -> restoreNav[0] = mGestureNavSwitchHelper.withGestureNavigationMode(),
                        true, /* expected */
                        false /* inputViewStarted */
                );
            }

            verifyInputViewStatusOnMainSync(
                () -> {
                    setDrawsImeNavBarAndSwitcherButton(true /* enabled */);
                    mActivity.showImeWithWindowInsetsController();
                },
                    () -> mActivity.showImeWithWindowInsetsController(),
                    true /* expected */,
                    true /* inputViewStarted */);
            assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();

        final var backButtonUiObject = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID));
        backButtonUiObject.click();
            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.
                // 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();
        }
    }

    /**
     * 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 */);

        final boolean isGestureMode = mGestureNavSwitchHelper.isGestureMode();

        final var restoreNav = new AutoCloseable[]{() -> {}};
        try {
            if (!isGestureMode) {
                //  Wait for onConfigurationChanged when changing navigation modes.
                verifyInputViewStatus(
                        () -> restoreNav[0] = mGestureNavSwitchHelper.withGestureNavigationMode(),
                        true, /* expected */
                        false /* inputViewStarted */
                );
            }

            verifyInputViewStatusOnMainSync(
                () -> {
                    setDrawsImeNavBarAndSwitcherButton(true /* enabled */);
                    mActivity.showImeWithWindowInsetsController();
                },
                    () -> mActivity.showImeWithWindowInsetsController(),
                    true /* expected */,
                    true /* inputViewStarted */);
            assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();

        final var backButtonUiObject = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID));
        backButtonUiObject.longClick();
            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.
                // 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,14 +968,26 @@ 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 */);

        final boolean isGestureMode = mGestureNavSwitchHelper.isGestureMode();

        final var restoreNav = new AutoCloseable[]{() -> {}};
        try {
            if (!isGestureMode) {
                //  Wait for onConfigurationChanged when changing navigation modes.
                verifyInputViewStatus(
                        () -> restoreNav[0] = mGestureNavSwitchHelper.withGestureNavigationMode(),
                        true, /* expected */
                        false /* inputViewStarted */
                );
            }

            verifyInputViewStatusOnMainSync(
                    () -> {
                        setDrawsImeNavBarAndSwitcherButton(true /* enabled */);
@@ -964,8 +999,8 @@ public class InputMethodServiceTest {

            final var initialInfo = mImm.getCurrentInputMethodInfo();

        final var imeSwitchButtonUiObject = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
        imeSwitchButtonUiObject.click();
            final var imeSwitcherButton = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
            imeSwitcherButton.click();
            mInstrumentation.waitForIdleSync();

            final var newInfo = mImm.getCurrentInputMethodInfo();
@@ -979,20 +1014,35 @@ public class InputMethodServiceTest {

            // 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 */);

        final boolean isGestureMode = mGestureNavSwitchHelper.isGestureMode();

        final var restoreNav = new AutoCloseable[]{() -> {}};
        try {
            if (!isGestureMode) {
                //  Wait for onConfigurationChanged when changing navigation modes.
                verifyInputViewStatus(
                        () -> restoreNav[0] = mGestureNavSwitchHelper.withGestureNavigationMode(),
                        true, /* expected */
                        false /* inputViewStarted */
                );
            }

            verifyInputViewStatusOnMainSync(
                    () -> {
                        setDrawsImeNavBarAndSwitcherButton(true /* enabled */);
@@ -1002,8 +1052,8 @@ public class InputMethodServiceTest {
                    true /* inputViewStarted */);
            assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue();

        final var imeSwitchButtonUiObject = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
        imeSwitchButtonUiObject.longClick();
            final var imeSwitcherButton = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
            imeSwitcherButton.longClick();
            mInstrumentation.waitForIdleSync();

            assertWithMessage("Input Method Switcher Menu is shown")
@@ -1013,6 +1063,9 @@ public class InputMethodServiceTest {

            // 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;
+1 −0
Original line number Diff line number Diff line
@@ -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"