Extend AutoShowTest to test more softInputMode flags
Extend AutoShowTest to test the behavior of combining various softInputMode flags: * SOFT_INPUT_STATE_UNSPECIFIED * SOFT_INPUT_STATE_HIDDEN * SOFT_INPUT_STATE_ALWAYS_HIDDEN * SOFT_INPUT_STATE_VISIBLE * SOFT_INPUT_STATE_ALWAYS_VISIBLE softInput adjustment flags: * SOFT_INPUT_ADJUST_UNSPECIFIED * SOFT_INPUT_ADJUST_RESIZE * SOFT_INPUT_ADJUST_PAN * SOFT_INPUT_ADJUST_NOTHING set or not set: * SOFT_INPUT_IS_FORWARD_NAVIGATION Flag SOFT_INPUT_STATE_UNCHANGED was not included for now as it requires more than one activities. Bug: 242838873 Bug: 77152727 Test: atest InputMethodStressTest Change-Id: I21ef8073d0b6a582c108141000e23847be6daf33
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user