Merge "Extend AutoShowTest to test more softInputMode flags"

This commit is contained in:
TreeHugger Robot
2022-10-14 12:48:22 +00:00
committed by Android (Google) Code Review
2 changed files with 138 additions and 15 deletions

View File

@@ -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();
}

View File

@@ -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);
}
}
}
}