diff options
| -rw-r--r-- | tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java | 113 | ||||
| -rw-r--r-- | tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java | 40 |
2 files changed, 138 insertions, 15 deletions
diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java index c84c2bcf19c6..92ea029bf469 100644 --- a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java +++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java @@ -18,9 +18,8 @@ package com.android.inputmethod.stresstest; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; -import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; -import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED; +import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyImeIsAlwaysHidden; import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntil; import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntilImeIsShown; @@ -30,19 +29,27 @@ import android.content.Intent; import android.os.Bundle; import android.platform.test.annotations.RootPermissionTest; import android.platform.test.rule.UnlockScreenRule; +import android.view.WindowManager; import android.widget.EditText; import android.widget.LinearLayout; import androidx.annotation.Nullable; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import java.util.ArrayList; +import java.util.List; + +/** + * Tests to verify the "auto show" behavior in {@code InputMethodManagerService} when the window + * gaining the focus to start the input. + */ @RootPermissionTest -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) public final class AutoShowTest { @Rule @@ -52,18 +59,95 @@ public final class AutoShowTest { public ScreenCaptureRule mScreenCaptureRule = new ScreenCaptureRule("/sdcard/InputMethodStressTest"); + private static final int[] SOFT_INPUT_VISIBILITY_FLAGS = + new int[] { + WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED, + WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN, + WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN, + WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE, + WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE, + }; + + private static final int[] SOFT_INPUT_ADJUST_FLAGS = + new int[] { + WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED, + WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE, + WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN, + WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING + }; + + // TODO(b/240359838): add test case {@code Configuration.SCREENLAYOUT_SIZE_LARGE}. + @Parameterized.Parameters( + name = + "softInputVisibility={0}, softInputAdjustment={1}," + + " softInputModeIsForwardNavigation={2}") + public static List<Object[]> softInputModeConfigs() { + ArrayList<Object[]> params = new ArrayList<>(); + for (int softInputVisibility : SOFT_INPUT_VISIBILITY_FLAGS) { + for (int softInputAdjust : SOFT_INPUT_ADJUST_FLAGS) { + params.add(new Object[] {softInputVisibility, softInputAdjust, true}); + params.add(new Object[] {softInputVisibility, softInputAdjust, false}); + } + } + return params; + } + + private static final String SOFT_INPUT_FLAGS = "soft_input_flags"; + + private final int mSoftInputVisibility; + private final int mSoftInputAdjustment; + private final boolean mSoftInputIsForwardNavigation; + + public AutoShowTest( + int softInputVisibility, + int softInputAdjustment, + boolean softInputIsForwardNavigation) { + mSoftInputVisibility = softInputVisibility; + mSoftInputAdjustment = softInputAdjustment; + mSoftInputIsForwardNavigation = softInputIsForwardNavigation; + } + @Test public void autoShow() { Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); - Intent intent = new Intent() - .setAction(Intent.ACTION_MAIN) - .setClass(instrumentation.getContext(), TestActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + int flags = mSoftInputVisibility | mSoftInputAdjustment; + if (mSoftInputIsForwardNavigation) { + flags |= WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; + } + + Intent intent = + new Intent() + .setAction(Intent.ACTION_MAIN) + .setClass(instrumentation.getContext(), TestActivity.class) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + .putExtra(SOFT_INPUT_FLAGS, flags); TestActivity activity = (TestActivity) instrumentation.startActivitySync(intent); EditText editText = activity.getEditText(); waitOnMainUntil("activity should gain focus", editText::hasWindowFocus); - waitOnMainUntilImeIsShown(editText); + + if (mSoftInputVisibility == WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE + || mSoftInputVisibility + == WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) { + // IME will be auto-shown if softInputMode is set with flag: + // SOFT_INPUT_STATE_VISIBLE or SOFT_INPUT_STATE_ALWAYS_VISIBLE + waitOnMainUntilImeIsShown(editText); + } else if (mSoftInputVisibility == WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN + || mSoftInputVisibility + == WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN) { + // IME will be not be shown if softInputMode is set with flag: + // SOFT_INPUT_STATE_HIDDEN or SOFT_INPUT_STATE_ALWAYS_HIDDEN + verifyImeIsAlwaysHidden(editText); + } else { + // The current system behavior will choose to show IME automatically when navigating + // forward to an app that has no visibility state specified (i.e. + // SOFT_INPUT_STATE_UNSPECIFIED) with set SOFT_INPUT_ADJUST_RESIZE flag. + if (mSoftInputVisibility == WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED + && mSoftInputAdjustment == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE + && mSoftInputIsForwardNavigation) { + waitOnMainUntilImeIsShown(editText); + } + } } public static class TestActivity extends Activity { @@ -72,16 +156,15 @@ public final class AutoShowTest { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // IME will be auto-shown if the following conditions are met: - // 1. SoftInputMode state is SOFT_INPUT_STATE_UNSPECIFIED. - // 2. SoftInputMode adjust is SOFT_INPUT_ADJUST_RESIZE. - getWindow().setSoftInputMode(SOFT_INPUT_STATE_UNSPECIFIED | SOFT_INPUT_ADJUST_RESIZE); + int flags = getIntent().getIntExtra(SOFT_INPUT_FLAGS, 0); + getWindow().setSoftInputMode(flags); LinearLayout rootView = new LinearLayout(this); rootView.setOrientation(LinearLayout.VERTICAL); mEditText = new EditText(this); rootView.addView(mEditText, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)); setContentView(rootView); - // 3. The focused view is a text editor (View#onCheckIsTextEditor() returns true). + // Ensure the focused view is a text editor (View#onCheckIsTextEditor() returns true) to + // automatically display a soft input window. mEditText.requestFocus(); } diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java index ba2ba3c75bc2..b6d462c6203d 100644 --- a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java +++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java @@ -25,6 +25,8 @@ import android.view.WindowInsets; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.compatibility.common.util.ThrowingRunnable; + import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -33,6 +35,7 @@ import java.util.concurrent.atomic.AtomicReference; public final class ImeStressTestUtil { private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5); + private static final long VERIFY_DURATION = TimeUnit.SECONDS.toMillis(2); private ImeStressTestUtil() { } @@ -77,4 +80,41 @@ public final class ImeStressTestUtil { eventually(() -> assertWithMessage("IME should be hidden").that( callOnMainSync(() -> isImeShown(view))).isFalse(), TIMEOUT); } + + /** Verify IME is always hidden within the given time duration. */ + public static void verifyImeIsAlwaysHidden(View view) { + always( + () -> + assertWithMessage("IME should be hidden") + .that(callOnMainSync(() -> isImeShown(view))) + .isFalse(), + VERIFY_DURATION); + } + + /** + * Make sure that a {@link Runnable} always finishes without throwing a {@link Exception} in the + * given duration + * + * @param r The {@link Runnable} to run. + * @param timeoutMillis The number of milliseconds to wait for {@code r} to not throw + */ + public static void always(ThrowingRunnable r, long timeoutMillis) { + long start = System.currentTimeMillis(); + + while (true) { + try { + r.run(); + if (System.currentTimeMillis() - start >= timeoutMillis) { + return; + } + try { + Thread.sleep(100); + } catch (InterruptedException ignored) { + // Do nothing + } + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } } |