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

Commit bc287a10 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Extend AutoShowTest to test more softInputMode flags"

parents 6edba6e7 d0091597
Loading
Loading
Loading
Loading
+98 −15
Original line number Diff line number Diff line
@@ -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,19 +59,96 @@ 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()
        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);
                        .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);

        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 {
        private EditText mEditText;
@@ -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();
        }

+40 −0
Original line number Diff line number Diff line
@@ -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);
            }
        }
    }
}