Loading tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java +4 −3 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static com.android.inputmethod.stresstest.ImeStressTestUtil.UNFOCUSABLE_V import static com.android.inputmethod.stresstest.ImeStressTestUtil.callOnMainSync; import static com.android.inputmethod.stresstest.ImeStressTestUtil.getWindowAndSoftInputFlagParameters; import static com.android.inputmethod.stresstest.ImeStressTestUtil.hasUnfocusableWindowFlags; import static com.android.inputmethod.stresstest.ImeStressTestUtil.requestFocusAndVerify; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyImeAlwaysHiddenWithWindowFlagSet; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyImeIsAlwaysHidden; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyWindowAndViewFocus; Loading Loading @@ -225,7 +226,7 @@ public final class AutoShowTest { Intent intent1 = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity firstActivity = TestActivity.start(intent1); // Request view focus after app starts mInstrumentation.runOnMainSync(firstActivity::requestFocus); requestFocusAndVerify(firstActivity); Intent intent2 = createIntent( Loading @@ -252,7 +253,7 @@ public final class AutoShowTest { Intent intent1 = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent1); // Request view focus after app starts mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); // Create second TestActivity Intent intent2 = Loading Loading @@ -284,7 +285,7 @@ public final class AutoShowTest { Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request view focus after app starts mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); // Find the editText and click it UiObject2 editTextUiObject = Loading tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/DefaultImeVisibilityTest.java +3 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static com.android.compatibility.common.util.SystemUtil.eventually; import static com.android.inputmethod.stresstest.ImeStressTestUtil.REQUEST_FOCUS_ON_CREATE; import static com.android.inputmethod.stresstest.ImeStressTestUtil.TestActivity.createIntent; import static com.android.inputmethod.stresstest.ImeStressTestUtil.callOnMainSync; import static com.android.inputmethod.stresstest.ImeStressTestUtil.requestFocusAndVerify; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyWindowAndViewFocus; import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntilImeIsHidden; import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntilImeIsShown; Loading Loading @@ -96,7 +97,7 @@ public final class DefaultImeVisibilityTest { UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); eventually( () -> assertWithMessage("Display rotation should be updated.") assertWithMessage("Display rotation should have been updated") .that(uiDevice.getDisplayRotation()) .isEqualTo(mIsPortrait ? 0 : 1), TIMEOUT); Loading @@ -104,7 +105,7 @@ public final class DefaultImeVisibilityTest { for (int i = 0; i < NUM_TEST_ITERATIONS; i++) { // TODO(b/291752364): Remove the explicit focus request once the issue with view focus // change between fullscreen IME and actual editText is fixed. callOnMainSync(editText::requestFocus); requestFocusAndVerify(activity); verifyWindowAndViewFocus(editText, true, true); callOnMainSync(activity::showImeWithInputMethodManager); waitOnMainUntilImeIsShown(editText); Loading tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeOpenCloseStressTest.java +40 −59 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static com.android.inputmethod.stresstest.ImeStressTestUtil.callOnMainSyn import static com.android.inputmethod.stresstest.ImeStressTestUtil.getWindowAndSoftInputFlagParameters; import static com.android.inputmethod.stresstest.ImeStressTestUtil.hasUnfocusableWindowFlags; import static com.android.inputmethod.stresstest.ImeStressTestUtil.isImeShown; import static com.android.inputmethod.stresstest.ImeStressTestUtil.requestFocusAndVerify; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyImeAlwaysHiddenWithWindowFlagSet; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyImeIsAlwaysHidden; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyWindowAndViewFocus; Loading @@ -38,6 +39,9 @@ import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUnt import static com.google.common.truth.Truth.assertThat; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import android.app.Instrumentation; import android.content.Intent; import android.os.Build; Loading Loading @@ -96,7 +100,8 @@ public final class ImeOpenCloseStressTest { Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); // Test only once if window flags set to save time. int iterNum = hasUnfocusableWindowFlags(activity) ? 1 : NUM_TEST_ITERATIONS; for (int i = 0; i < iterNum; i++) { Loading @@ -106,21 +111,19 @@ public final class ImeOpenCloseStressTest { verifyShowBehavior(activity); callOnMainSync(activity::hideImeWithInputMethodManager); verifyHideBehavior(activity); } } @Test public void testShowHideWithInputMethodManager_waitingAnimationEnd() { assumeFalse("Has unfocusable window flags", hasUnfocusableWindowFlags(mWindowFocusFlags)); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); if (hasUnfocusableWindowFlags(activity)) { return; // Skip to save time. } activity.enableAnimationMonitoring(); EditText editText = activity.getEditText(); for (int i = 0; i < NUM_TEST_ITERATIONS; i++) { Loading @@ -128,12 +131,12 @@ public final class ImeOpenCloseStressTest { Log.i(TAG, msgPrefix + "start"); callOnMainSync(activity::showImeWithInputMethodManager); waitOnMainUntil( msgPrefix + "IME should be visible", msgPrefix + "IME should have been shown", () -> !activity.isAnimating() && isImeShown(editText)); callOnMainSync(activity::hideImeWithInputMethodManager); waitOnMainUntil( msgPrefix + "IME should be hidden", msgPrefix + "IME should have been hidden", () -> !activity.isAnimating() && !isImeShown(editText)); } } Loading @@ -141,13 +144,13 @@ public final class ImeOpenCloseStressTest { @Test public void testShowHideWithInputMethodManager_intervalAfterHide() { // Regression test for b/221483132 assumeFalse("Has unfocusable window flags", hasUnfocusableWindowFlags(mWindowFocusFlags)); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); if (hasUnfocusableWindowFlags(activity)) { return; // Skip to save time. } requestFocusAndVerify(activity); // Intervals = 10, 20, 30, ..., 100, 150, 200, ... List<Integer> intervals = new ArrayList<>(); for (int i = 10; i < 100; i += 10) intervals.add(i); Loading @@ -165,14 +168,12 @@ public final class ImeOpenCloseStressTest { @Test public void testShowHideWithInputMethodManager_inSameFrame() { assumeFalse("Has unfocusable window flags", hasUnfocusableWindowFlags(mWindowFocusFlags)); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); if (hasUnfocusableWindowFlags(activity)) { return; // Skip to save time. } // hidden -> show -> hide mInstrumentation.runOnMainSync( () -> { Loading Loading @@ -256,13 +257,12 @@ public final class ImeOpenCloseStressTest { @Test public void testShowHideWithWindowInsetsController_waitingVisibilityChange() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); // Test only once if window flags set to save time. int iterNum = hasUnfocusableWindowFlags(activity) ? 1 : NUM_TEST_ITERATIONS; for (int i = 0; i < iterNum; i++) { Loading @@ -277,17 +277,13 @@ public final class ImeOpenCloseStressTest { @Test public void testShowHideWithWindowInsetsController_waitingAnimationEnd() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); assumeFalse("Has unfocusable window flags", hasUnfocusableWindowFlags(mWindowFocusFlags)); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); if (hasUnfocusableWindowFlags(activity)) { return; // Skip to save time. } activity.enableAnimationMonitoring(); EditText editText = activity.getEditText(); for (int i = 0; i < NUM_TEST_ITERATIONS; i++) { Loading @@ -295,29 +291,25 @@ public final class ImeOpenCloseStressTest { Log.i(TAG, msgPrefix + "start"); mInstrumentation.runOnMainSync(activity::showImeWithWindowInsetsController); waitOnMainUntil( msgPrefix + "IME should be visible", msgPrefix + "IME should have been shown", () -> !activity.isAnimating() && isImeShown(editText)); mInstrumentation.runOnMainSync(activity::hideImeWithWindowInsetsController); waitOnMainUntil( msgPrefix + "IME should be hidden", msgPrefix + "IME should have been hidden", () -> !activity.isAnimating() && !isImeShown(editText)); } } @Test public void testShowHideWithWindowInsetsController_intervalAfterHide() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); assumeFalse("Has unfocusable window flags", hasUnfocusableWindowFlags(mWindowFocusFlags)); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); if (hasUnfocusableWindowFlags(activity)) { return; // Skip to save time. } // Intervals = 10, 20, 30, ..., 100, 150, 200, ... List<Integer> intervals = new ArrayList<>(); for (int i = 10; i < 100; i += 10) intervals.add(i); Loading @@ -335,17 +327,13 @@ public final class ImeOpenCloseStressTest { @Test public void testShowHideWithWindowInsetsController_inSameFrame() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); assumeFalse("Has unfocusable window flags", hasUnfocusableWindowFlags(mWindowFocusFlags)); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); if (hasUnfocusableWindowFlags(activity)) { return; // Skip to save time. } // hidden -> show -> hide mInstrumentation.runOnMainSync( () -> { Loading Loading @@ -377,9 +365,7 @@ public final class ImeOpenCloseStressTest { @Test public void testShowWithWindowInsetsController_onCreate_requestFocus() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); // Show with InputMethodManager at onCreate() Intent intent = createIntent( Loading @@ -394,10 +380,8 @@ public final class ImeOpenCloseStressTest { @Test public void testShowWithWindowInsetsController_onCreate_notRequestFocus() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } // Show and hide with InputMethodManager at onCreate() assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); // Show and hide with WindowInsetsController at onCreate() Intent intent = createIntent( mWindowFocusFlags, Loading @@ -411,10 +395,8 @@ public final class ImeOpenCloseStressTest { @Test public void testShowWithWindowInsetsController_afterStart_notRequestFocus() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } // Show and hide with InputMethodManager at onCreate() assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); // Show and hide with WindowInsetsController at onCreate() Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); mInstrumentation.runOnMainSync(activity::showImeWithWindowInsetsController); Loading @@ -425,7 +407,8 @@ public final class ImeOpenCloseStressTest { /** * Test IME hidden by calling show and hide IME consecutively with * {@link android.view.WindowInsetsController} APIs in {@link android.app.Activity#onCreate}. * {@link android.view.WindowInsetsController} APIs in * {@link android.app.Activity#onCreate}. * * <p> Note for developers: Use {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_UNCHANGED} * window flag to avoid some softInputMode visibility flags may take presence over Loading @@ -436,13 +419,11 @@ public final class ImeOpenCloseStressTest { */ @Test public void testHideWithWindowInsetsController_onCreate_requestFocus() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); if (mSoftInputFlags != SOFT_INPUT_STATE_UNCHANGED) { return; } // Show and hide with InputMethodManager at onCreate() // Show and hide with WindowInsetsController at onCreate() Intent intent = createIntent( mWindowFocusFlags, Loading tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java +52 −21 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.LinearLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.test.platform.app.InstrumentationRegistry; Loading Loading @@ -148,6 +149,14 @@ public final class ImeStressTestUtil { return result.get(); } /** * Requests EditText view focus on the main thread, and assert this returns {@code true}. */ public static void requestFocusAndVerify(TestActivity activity) { boolean result = callOnMainSync(activity::requestFocus); assertWithMessage("View focus request should have succeeded").that(result).isTrue(); } /** * Waits until {@code pred} returns true, or throws on timeout. * Loading @@ -161,7 +170,7 @@ public final class ImeStressTestUtil { public static void waitOnMainUntilImeIsShown(View view) { eventually( () -> assertWithMessage("IME should be shown") assertWithMessage("IME should have been shown") .that(callOnMainSync(() -> isImeShown(view))) .isTrue(), TIMEOUT); Loading @@ -171,27 +180,28 @@ public final class ImeStressTestUtil { public static void waitOnMainUntilImeIsHidden(View view) { eventually( () -> assertWithMessage("IME should be hidden") assertWithMessage("IME should have been hidden") .that(callOnMainSync(() -> isImeShown(view))) .isFalse(), TIMEOUT); } /** Waits until window get focus, or throws on timeout. */ /** Waits until window gains focus, or throws on timeout. */ public static void waitOnMainUntilWindowGainsFocus(View view) { eventually( () -> assertWithMessage("Window should gain focus") assertWithMessage( "Window should have gained focus; value of hasWindowFocus:") .that(callOnMainSync(view::hasWindowFocus)) .isTrue(), TIMEOUT); } /** Waits until view get focus, or throws on timeout. */ /** Waits until view gains focus, or throws on timeout. */ public static void waitOnMainUntilViewGainsFocus(View view) { eventually( () -> assertWithMessage("View should gain focus") assertWithMessage("View should have gained focus; value of hasFocus:") .that(callOnMainSync(view::hasFocus)) .isTrue(), TIMEOUT); Loading @@ -201,7 +211,7 @@ public final class ImeStressTestUtil { public static void verifyImeIsAlwaysHidden(View view) { always( () -> assertWithMessage("IME should be hidden") assertWithMessage("IME should have been hidden") .that(callOnMainSync(() -> isImeShown(view))) .isFalse(), TIMEOUT); Loading @@ -211,7 +221,8 @@ public final class ImeStressTestUtil { public static void verifyWindowNeverGainsFocus(View view) { always( () -> assertWithMessage("window should never gain focus") assertWithMessage( "Window should not have gained focus; value of hasWindowFocus:") .that(callOnMainSync(view::hasWindowFocus)) .isFalse(), TIMEOUT); Loading @@ -221,7 +232,7 @@ public final class ImeStressTestUtil { public static void verifyViewNeverGainsFocus(View view) { always( () -> assertWithMessage("view should never gain ime focus") assertWithMessage("View should not have gained focus; value of hasFocus:") .that(callOnMainSync(view::hasFocus)) .isFalse(), TIMEOUT); Loading Loading @@ -254,8 +265,23 @@ public final class ImeStressTestUtil { } } /** * Returns {@code true} if the activity can't receive IME focus, based on its window flags, * and {@code false} otherwise. * * @param activity the activity to check. */ public static boolean hasUnfocusableWindowFlags(Activity activity) { int windowFlags = activity.getWindow().getAttributes().flags; return hasUnfocusableWindowFlags(activity.getWindow().getAttributes().flags); } /** * Returns {@code true} if the activity can't receive IME focus, based on its window flags, * and {@code false} otherwise. * * @param windowFlags the window flags to check. */ public static boolean hasUnfocusableWindowFlags(int windowFlags) { return (windowFlags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0 || (windowFlags & LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0 || (windowFlags & LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0; Loading Loading @@ -302,22 +328,26 @@ public final class ImeStressTestUtil { private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback = new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) { @NonNull @Override public WindowInsetsAnimation.Bounds onStart( WindowInsetsAnimation animation, WindowInsetsAnimation.Bounds bounds) { @NonNull WindowInsetsAnimation animation, @NonNull WindowInsetsAnimation.Bounds bounds) { mIsAnimating = true; return super.onStart(animation, bounds); } @Override public void onEnd(WindowInsetsAnimation animation) { public void onEnd(@NonNull WindowInsetsAnimation animation) { super.onEnd(animation); mIsAnimating = false; } @NonNull @Override public WindowInsets onProgress( WindowInsets insets, List<WindowInsetsAnimation> runningAnimations) { @NonNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations) { return insets; } }; Loading Loading @@ -394,7 +424,7 @@ public final class ImeStressTestUtil { getInputMethodManager() .showSoftInput(mEditText, 0 /* flags */); if (showResult) { Log.i(TAG, "IMM#showSoftInput successfully"); Log.i(TAG, "IMM#showSoftInput succeeded"); } else { Log.i(TAG, "IMM#showSoftInput failed"); } Loading @@ -407,7 +437,7 @@ public final class ImeStressTestUtil { getInputMethodManager() .hideSoftInputFromWindow(mEditText.getWindowToken(), 0 /* flags */); if (hideResult) { Log.i(TAG, "IMM#hideSoftInput successfully"); Log.i(TAG, "IMM#hideSoftInput succeeded"); } else { Log.i(TAG, "IMM#hideSoftInput failed"); } Loading @@ -421,7 +451,7 @@ public final class ImeStressTestUtil { } Log.i(TAG, "showImeWithWIC()"); WindowInsetsController windowInsetsController = mEditText.getWindowInsetsController(); assertWithMessage("WindowInsetsController shouldn't be null.") assertWithMessage("WindowInsetsController") .that(windowInsetsController) .isNotNull(); windowInsetsController.show(WindowInsets.Type.ime()); Loading @@ -434,7 +464,7 @@ public final class ImeStressTestUtil { } Log.i(TAG, "hideImeWithWIC()"); WindowInsetsController windowInsetsController = mEditText.getWindowInsetsController(); assertWithMessage("WindowInsetsController shouldn't be null.") assertWithMessage("WindowInsetsController") .that(windowInsetsController) .isNotNull(); windowInsetsController.hide(WindowInsets.Type.ime()); Loading Loading @@ -482,13 +512,14 @@ public final class ImeStressTestUtil { return mIsAnimating; } public void requestFocus() { boolean requestFocusResult = getEditText().requestFocus(); public boolean requestFocus() { boolean requestFocusResult = mEditText.requestFocus(); if (requestFocusResult) { Log.i(TAG, "Request focus successfully"); Log.i(TAG, "View#requestFocus succeeded"); } else { Log.i(TAG, "Request focus failed"); Log.i(TAG, "View#requestFocus failed"); } return requestFocusResult; } } } Loading
tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/AutoShowTest.java +4 −3 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static com.android.inputmethod.stresstest.ImeStressTestUtil.UNFOCUSABLE_V import static com.android.inputmethod.stresstest.ImeStressTestUtil.callOnMainSync; import static com.android.inputmethod.stresstest.ImeStressTestUtil.getWindowAndSoftInputFlagParameters; import static com.android.inputmethod.stresstest.ImeStressTestUtil.hasUnfocusableWindowFlags; import static com.android.inputmethod.stresstest.ImeStressTestUtil.requestFocusAndVerify; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyImeAlwaysHiddenWithWindowFlagSet; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyImeIsAlwaysHidden; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyWindowAndViewFocus; Loading Loading @@ -225,7 +226,7 @@ public final class AutoShowTest { Intent intent1 = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity firstActivity = TestActivity.start(intent1); // Request view focus after app starts mInstrumentation.runOnMainSync(firstActivity::requestFocus); requestFocusAndVerify(firstActivity); Intent intent2 = createIntent( Loading @@ -252,7 +253,7 @@ public final class AutoShowTest { Intent intent1 = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent1); // Request view focus after app starts mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); // Create second TestActivity Intent intent2 = Loading Loading @@ -284,7 +285,7 @@ public final class AutoShowTest { Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request view focus after app starts mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); // Find the editText and click it UiObject2 editTextUiObject = Loading
tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/DefaultImeVisibilityTest.java +3 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static com.android.compatibility.common.util.SystemUtil.eventually; import static com.android.inputmethod.stresstest.ImeStressTestUtil.REQUEST_FOCUS_ON_CREATE; import static com.android.inputmethod.stresstest.ImeStressTestUtil.TestActivity.createIntent; import static com.android.inputmethod.stresstest.ImeStressTestUtil.callOnMainSync; import static com.android.inputmethod.stresstest.ImeStressTestUtil.requestFocusAndVerify; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyWindowAndViewFocus; import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntilImeIsHidden; import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUntilImeIsShown; Loading Loading @@ -96,7 +97,7 @@ public final class DefaultImeVisibilityTest { UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); eventually( () -> assertWithMessage("Display rotation should be updated.") assertWithMessage("Display rotation should have been updated") .that(uiDevice.getDisplayRotation()) .isEqualTo(mIsPortrait ? 0 : 1), TIMEOUT); Loading @@ -104,7 +105,7 @@ public final class DefaultImeVisibilityTest { for (int i = 0; i < NUM_TEST_ITERATIONS; i++) { // TODO(b/291752364): Remove the explicit focus request once the issue with view focus // change between fullscreen IME and actual editText is fixed. callOnMainSync(editText::requestFocus); requestFocusAndVerify(activity); verifyWindowAndViewFocus(editText, true, true); callOnMainSync(activity::showImeWithInputMethodManager); waitOnMainUntilImeIsShown(editText); Loading
tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeOpenCloseStressTest.java +40 −59 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static com.android.inputmethod.stresstest.ImeStressTestUtil.callOnMainSyn import static com.android.inputmethod.stresstest.ImeStressTestUtil.getWindowAndSoftInputFlagParameters; import static com.android.inputmethod.stresstest.ImeStressTestUtil.hasUnfocusableWindowFlags; import static com.android.inputmethod.stresstest.ImeStressTestUtil.isImeShown; import static com.android.inputmethod.stresstest.ImeStressTestUtil.requestFocusAndVerify; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyImeAlwaysHiddenWithWindowFlagSet; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyImeIsAlwaysHidden; import static com.android.inputmethod.stresstest.ImeStressTestUtil.verifyWindowAndViewFocus; Loading @@ -38,6 +39,9 @@ import static com.android.inputmethod.stresstest.ImeStressTestUtil.waitOnMainUnt import static com.google.common.truth.Truth.assertThat; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import android.app.Instrumentation; import android.content.Intent; import android.os.Build; Loading Loading @@ -96,7 +100,8 @@ public final class ImeOpenCloseStressTest { Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); // Test only once if window flags set to save time. int iterNum = hasUnfocusableWindowFlags(activity) ? 1 : NUM_TEST_ITERATIONS; for (int i = 0; i < iterNum; i++) { Loading @@ -106,21 +111,19 @@ public final class ImeOpenCloseStressTest { verifyShowBehavior(activity); callOnMainSync(activity::hideImeWithInputMethodManager); verifyHideBehavior(activity); } } @Test public void testShowHideWithInputMethodManager_waitingAnimationEnd() { assumeFalse("Has unfocusable window flags", hasUnfocusableWindowFlags(mWindowFocusFlags)); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); if (hasUnfocusableWindowFlags(activity)) { return; // Skip to save time. } activity.enableAnimationMonitoring(); EditText editText = activity.getEditText(); for (int i = 0; i < NUM_TEST_ITERATIONS; i++) { Loading @@ -128,12 +131,12 @@ public final class ImeOpenCloseStressTest { Log.i(TAG, msgPrefix + "start"); callOnMainSync(activity::showImeWithInputMethodManager); waitOnMainUntil( msgPrefix + "IME should be visible", msgPrefix + "IME should have been shown", () -> !activity.isAnimating() && isImeShown(editText)); callOnMainSync(activity::hideImeWithInputMethodManager); waitOnMainUntil( msgPrefix + "IME should be hidden", msgPrefix + "IME should have been hidden", () -> !activity.isAnimating() && !isImeShown(editText)); } } Loading @@ -141,13 +144,13 @@ public final class ImeOpenCloseStressTest { @Test public void testShowHideWithInputMethodManager_intervalAfterHide() { // Regression test for b/221483132 assumeFalse("Has unfocusable window flags", hasUnfocusableWindowFlags(mWindowFocusFlags)); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); if (hasUnfocusableWindowFlags(activity)) { return; // Skip to save time. } requestFocusAndVerify(activity); // Intervals = 10, 20, 30, ..., 100, 150, 200, ... List<Integer> intervals = new ArrayList<>(); for (int i = 10; i < 100; i += 10) intervals.add(i); Loading @@ -165,14 +168,12 @@ public final class ImeOpenCloseStressTest { @Test public void testShowHideWithInputMethodManager_inSameFrame() { assumeFalse("Has unfocusable window flags", hasUnfocusableWindowFlags(mWindowFocusFlags)); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); if (hasUnfocusableWindowFlags(activity)) { return; // Skip to save time. } // hidden -> show -> hide mInstrumentation.runOnMainSync( () -> { Loading Loading @@ -256,13 +257,12 @@ public final class ImeOpenCloseStressTest { @Test public void testShowHideWithWindowInsetsController_waitingVisibilityChange() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); // Test only once if window flags set to save time. int iterNum = hasUnfocusableWindowFlags(activity) ? 1 : NUM_TEST_ITERATIONS; for (int i = 0; i < iterNum; i++) { Loading @@ -277,17 +277,13 @@ public final class ImeOpenCloseStressTest { @Test public void testShowHideWithWindowInsetsController_waitingAnimationEnd() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); assumeFalse("Has unfocusable window flags", hasUnfocusableWindowFlags(mWindowFocusFlags)); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); if (hasUnfocusableWindowFlags(activity)) { return; // Skip to save time. } activity.enableAnimationMonitoring(); EditText editText = activity.getEditText(); for (int i = 0; i < NUM_TEST_ITERATIONS; i++) { Loading @@ -295,29 +291,25 @@ public final class ImeOpenCloseStressTest { Log.i(TAG, msgPrefix + "start"); mInstrumentation.runOnMainSync(activity::showImeWithWindowInsetsController); waitOnMainUntil( msgPrefix + "IME should be visible", msgPrefix + "IME should have been shown", () -> !activity.isAnimating() && isImeShown(editText)); mInstrumentation.runOnMainSync(activity::hideImeWithWindowInsetsController); waitOnMainUntil( msgPrefix + "IME should be hidden", msgPrefix + "IME should have been hidden", () -> !activity.isAnimating() && !isImeShown(editText)); } } @Test public void testShowHideWithWindowInsetsController_intervalAfterHide() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); assumeFalse("Has unfocusable window flags", hasUnfocusableWindowFlags(mWindowFocusFlags)); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); if (hasUnfocusableWindowFlags(activity)) { return; // Skip to save time. } // Intervals = 10, 20, 30, ..., 100, 150, 200, ... List<Integer> intervals = new ArrayList<>(); for (int i = 10; i < 100; i += 10) intervals.add(i); Loading @@ -335,17 +327,13 @@ public final class ImeOpenCloseStressTest { @Test public void testShowHideWithWindowInsetsController_inSameFrame() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); assumeFalse("Has unfocusable window flags", hasUnfocusableWindowFlags(mWindowFocusFlags)); Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); // Request focus after app starts to avoid triggering auto-show behavior. mInstrumentation.runOnMainSync(activity::requestFocus); requestFocusAndVerify(activity); if (hasUnfocusableWindowFlags(activity)) { return; // Skip to save time. } // hidden -> show -> hide mInstrumentation.runOnMainSync( () -> { Loading Loading @@ -377,9 +365,7 @@ public final class ImeOpenCloseStressTest { @Test public void testShowWithWindowInsetsController_onCreate_requestFocus() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); // Show with InputMethodManager at onCreate() Intent intent = createIntent( Loading @@ -394,10 +380,8 @@ public final class ImeOpenCloseStressTest { @Test public void testShowWithWindowInsetsController_onCreate_notRequestFocus() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } // Show and hide with InputMethodManager at onCreate() assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); // Show and hide with WindowInsetsController at onCreate() Intent intent = createIntent( mWindowFocusFlags, Loading @@ -411,10 +395,8 @@ public final class ImeOpenCloseStressTest { @Test public void testShowWithWindowInsetsController_afterStart_notRequestFocus() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } // Show and hide with InputMethodManager at onCreate() assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); // Show and hide with WindowInsetsController at onCreate() Intent intent = createIntent(mWindowFocusFlags, mSoftInputFlags, Collections.emptyList()); TestActivity activity = TestActivity.start(intent); mInstrumentation.runOnMainSync(activity::showImeWithWindowInsetsController); Loading @@ -425,7 +407,8 @@ public final class ImeOpenCloseStressTest { /** * Test IME hidden by calling show and hide IME consecutively with * {@link android.view.WindowInsetsController} APIs in {@link android.app.Activity#onCreate}. * {@link android.view.WindowInsetsController} APIs in * {@link android.app.Activity#onCreate}. * * <p> Note for developers: Use {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_UNCHANGED} * window flag to avoid some softInputMode visibility flags may take presence over Loading @@ -436,13 +419,11 @@ public final class ImeOpenCloseStressTest { */ @Test public void testHideWithWindowInsetsController_onCreate_requestFocus() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { return; } assumeTrue("Is at least Android R", Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); if (mSoftInputFlags != SOFT_INPUT_STATE_UNCHANGED) { return; } // Show and hide with InputMethodManager at onCreate() // Show and hide with WindowInsetsController at onCreate() Intent intent = createIntent( mWindowFocusFlags, Loading
tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java +52 −21 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.LinearLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.test.platform.app.InstrumentationRegistry; Loading Loading @@ -148,6 +149,14 @@ public final class ImeStressTestUtil { return result.get(); } /** * Requests EditText view focus on the main thread, and assert this returns {@code true}. */ public static void requestFocusAndVerify(TestActivity activity) { boolean result = callOnMainSync(activity::requestFocus); assertWithMessage("View focus request should have succeeded").that(result).isTrue(); } /** * Waits until {@code pred} returns true, or throws on timeout. * Loading @@ -161,7 +170,7 @@ public final class ImeStressTestUtil { public static void waitOnMainUntilImeIsShown(View view) { eventually( () -> assertWithMessage("IME should be shown") assertWithMessage("IME should have been shown") .that(callOnMainSync(() -> isImeShown(view))) .isTrue(), TIMEOUT); Loading @@ -171,27 +180,28 @@ public final class ImeStressTestUtil { public static void waitOnMainUntilImeIsHidden(View view) { eventually( () -> assertWithMessage("IME should be hidden") assertWithMessage("IME should have been hidden") .that(callOnMainSync(() -> isImeShown(view))) .isFalse(), TIMEOUT); } /** Waits until window get focus, or throws on timeout. */ /** Waits until window gains focus, or throws on timeout. */ public static void waitOnMainUntilWindowGainsFocus(View view) { eventually( () -> assertWithMessage("Window should gain focus") assertWithMessage( "Window should have gained focus; value of hasWindowFocus:") .that(callOnMainSync(view::hasWindowFocus)) .isTrue(), TIMEOUT); } /** Waits until view get focus, or throws on timeout. */ /** Waits until view gains focus, or throws on timeout. */ public static void waitOnMainUntilViewGainsFocus(View view) { eventually( () -> assertWithMessage("View should gain focus") assertWithMessage("View should have gained focus; value of hasFocus:") .that(callOnMainSync(view::hasFocus)) .isTrue(), TIMEOUT); Loading @@ -201,7 +211,7 @@ public final class ImeStressTestUtil { public static void verifyImeIsAlwaysHidden(View view) { always( () -> assertWithMessage("IME should be hidden") assertWithMessage("IME should have been hidden") .that(callOnMainSync(() -> isImeShown(view))) .isFalse(), TIMEOUT); Loading @@ -211,7 +221,8 @@ public final class ImeStressTestUtil { public static void verifyWindowNeverGainsFocus(View view) { always( () -> assertWithMessage("window should never gain focus") assertWithMessage( "Window should not have gained focus; value of hasWindowFocus:") .that(callOnMainSync(view::hasWindowFocus)) .isFalse(), TIMEOUT); Loading @@ -221,7 +232,7 @@ public final class ImeStressTestUtil { public static void verifyViewNeverGainsFocus(View view) { always( () -> assertWithMessage("view should never gain ime focus") assertWithMessage("View should not have gained focus; value of hasFocus:") .that(callOnMainSync(view::hasFocus)) .isFalse(), TIMEOUT); Loading Loading @@ -254,8 +265,23 @@ public final class ImeStressTestUtil { } } /** * Returns {@code true} if the activity can't receive IME focus, based on its window flags, * and {@code false} otherwise. * * @param activity the activity to check. */ public static boolean hasUnfocusableWindowFlags(Activity activity) { int windowFlags = activity.getWindow().getAttributes().flags; return hasUnfocusableWindowFlags(activity.getWindow().getAttributes().flags); } /** * Returns {@code true} if the activity can't receive IME focus, based on its window flags, * and {@code false} otherwise. * * @param windowFlags the window flags to check. */ public static boolean hasUnfocusableWindowFlags(int windowFlags) { return (windowFlags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0 || (windowFlags & LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0 || (windowFlags & LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0; Loading Loading @@ -302,22 +328,26 @@ public final class ImeStressTestUtil { private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback = new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) { @NonNull @Override public WindowInsetsAnimation.Bounds onStart( WindowInsetsAnimation animation, WindowInsetsAnimation.Bounds bounds) { @NonNull WindowInsetsAnimation animation, @NonNull WindowInsetsAnimation.Bounds bounds) { mIsAnimating = true; return super.onStart(animation, bounds); } @Override public void onEnd(WindowInsetsAnimation animation) { public void onEnd(@NonNull WindowInsetsAnimation animation) { super.onEnd(animation); mIsAnimating = false; } @NonNull @Override public WindowInsets onProgress( WindowInsets insets, List<WindowInsetsAnimation> runningAnimations) { @NonNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations) { return insets; } }; Loading Loading @@ -394,7 +424,7 @@ public final class ImeStressTestUtil { getInputMethodManager() .showSoftInput(mEditText, 0 /* flags */); if (showResult) { Log.i(TAG, "IMM#showSoftInput successfully"); Log.i(TAG, "IMM#showSoftInput succeeded"); } else { Log.i(TAG, "IMM#showSoftInput failed"); } Loading @@ -407,7 +437,7 @@ public final class ImeStressTestUtil { getInputMethodManager() .hideSoftInputFromWindow(mEditText.getWindowToken(), 0 /* flags */); if (hideResult) { Log.i(TAG, "IMM#hideSoftInput successfully"); Log.i(TAG, "IMM#hideSoftInput succeeded"); } else { Log.i(TAG, "IMM#hideSoftInput failed"); } Loading @@ -421,7 +451,7 @@ public final class ImeStressTestUtil { } Log.i(TAG, "showImeWithWIC()"); WindowInsetsController windowInsetsController = mEditText.getWindowInsetsController(); assertWithMessage("WindowInsetsController shouldn't be null.") assertWithMessage("WindowInsetsController") .that(windowInsetsController) .isNotNull(); windowInsetsController.show(WindowInsets.Type.ime()); Loading @@ -434,7 +464,7 @@ public final class ImeStressTestUtil { } Log.i(TAG, "hideImeWithWIC()"); WindowInsetsController windowInsetsController = mEditText.getWindowInsetsController(); assertWithMessage("WindowInsetsController shouldn't be null.") assertWithMessage("WindowInsetsController") .that(windowInsetsController) .isNotNull(); windowInsetsController.hide(WindowInsets.Type.ime()); Loading Loading @@ -482,13 +512,14 @@ public final class ImeStressTestUtil { return mIsAnimating; } public void requestFocus() { boolean requestFocusResult = getEditText().requestFocus(); public boolean requestFocus() { boolean requestFocusResult = mEditText.requestFocus(); if (requestFocusResult) { Log.i(TAG, "Request focus successfully"); Log.i(TAG, "View#requestFocus succeeded"); } else { Log.i(TAG, "Request focus failed"); Log.i(TAG, "View#requestFocus failed"); } return requestFocusResult; } } }