From 08603e695f9500893709b5ff746d1dff5b5d8320 Mon Sep 17 00:00:00 2001 From: Kohsuke Yatoh Date: Tue, 3 Aug 2021 17:32:20 -0700 Subject: [PATCH] Initial commit of InputMethodStressTest. This CL added a simple test of showing and hiding IME for 100 times. TODOs: 1. Add more complicated flows (such as notification). 2. Check IME visibility in several points (WindowManager dump, SurfaceFlinger dump, etc), not just the inset that the app received. Bug: 195468725 Test: atest InputMethodStressTest Change-Id: I1959225a7396d17750d799e11c42eb1899fe5bb9 --- tests/InputMethodStressTest/Android.bp | 35 ++++++++ .../InputMethodStressTest/AndroidManifest.xml | 28 +++++++ tests/InputMethodStressTest/AndroidTest.xml | 29 +++++++ tests/InputMethodStressTest/OWNERS | 3 + .../inputmethod/ImeOpenCloseStressTest.java | 79 +++++++++++++++++++ .../com/android/inputmethod/TestActivity.java | 64 +++++++++++++++ 6 files changed, 238 insertions(+) create mode 100644 tests/InputMethodStressTest/Android.bp create mode 100644 tests/InputMethodStressTest/AndroidManifest.xml create mode 100644 tests/InputMethodStressTest/AndroidTest.xml create mode 100644 tests/InputMethodStressTest/OWNERS create mode 100644 tests/InputMethodStressTest/src/com/android/inputmethod/ImeOpenCloseStressTest.java create mode 100644 tests/InputMethodStressTest/src/com/android/inputmethod/TestActivity.java diff --git a/tests/InputMethodStressTest/Android.bp b/tests/InputMethodStressTest/Android.bp new file mode 100644 index 0000000000000..131611d28f0a7 --- /dev/null +++ b/tests/InputMethodStressTest/Android.bp @@ -0,0 +1,35 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test { + name: "InputMethodStressTest", + srcs: ["src/**/*.java"], + libs: ["android.test.runner"], + static_libs: [ + "androidx.test.ext.junit", + "androidx.test.uiautomator_uiautomator", + "compatibility-device-util-axt", + "platform-test-annotations", + "truth-prebuilt", + ], + test_suites: [ + "general-tests", + "vts", + ], + sdk_version: "31", +} diff --git a/tests/InputMethodStressTest/AndroidManifest.xml b/tests/InputMethodStressTest/AndroidManifest.xml new file mode 100644 index 0000000000000..e5d65188f7adb --- /dev/null +++ b/tests/InputMethodStressTest/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + diff --git a/tests/InputMethodStressTest/AndroidTest.xml b/tests/InputMethodStressTest/AndroidTest.xml new file mode 100644 index 0000000000000..b194010a985a8 --- /dev/null +++ b/tests/InputMethodStressTest/AndroidTest.xml @@ -0,0 +1,29 @@ + + + + diff --git a/tests/InputMethodStressTest/OWNERS b/tests/InputMethodStressTest/OWNERS new file mode 100644 index 0000000000000..6bb4b17ed4eb4 --- /dev/null +++ b/tests/InputMethodStressTest/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 34867 + +include /services/core/java/com/android/server/inputmethod/OWNERS diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/ImeOpenCloseStressTest.java b/tests/InputMethodStressTest/src/com/android/inputmethod/ImeOpenCloseStressTest.java new file mode 100644 index 0000000000000..5427fd8332098 --- /dev/null +++ b/tests/InputMethodStressTest/src/com/android/inputmethod/ImeOpenCloseStressTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.stresstest; + +import static com.android.compatibility.common.util.SystemUtil.eventually; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.Instrumentation; +import android.content.Intent; +import android.platform.test.annotations.RootPermissionTest; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +@RootPermissionTest +@RunWith(AndroidJUnit4.class) +public class ImeOpenCloseStressTest { + + private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5); + private static final int NUM_TEST_ITERATIONS = 100; + + private Instrumentation mInstrumentation; + + @Test + public void test() { + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + Intent intent = new Intent() + .setAction(Intent.ACTION_MAIN) + .setClass(mInstrumentation.getContext(), TestActivity.class) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + TestActivity activity = (TestActivity) mInstrumentation.startActivitySync(intent); + eventually(() -> assertThat(callOnMainSync(activity::hasWindowFocus)).isTrue(), TIMEOUT); + for (int i = 0; i < NUM_TEST_ITERATIONS; i++) { + mInstrumentation.runOnMainSync(activity::showIme); + eventually(() -> assertThat(callOnMainSync(activity::isImeShown)).isTrue(), TIMEOUT); + mInstrumentation.runOnMainSync(activity::hideIme); + eventually(() -> assertThat(callOnMainSync(activity::isImeShown)).isFalse(), TIMEOUT); + } + } + + private V callOnMainSync(Callable callable) { + AtomicReference result = new AtomicReference<>(); + AtomicReference thrownException = new AtomicReference<>(); + mInstrumentation.runOnMainSync(() -> { + try { + result.set(callable.call()); + } catch (Exception e) { + thrownException.set(e); + } + }); + if (thrownException.get() != null) { + throw new RuntimeException("Exception thrown from Main thread", thrownException.get()); + } + return result.get(); + } +} diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/TestActivity.java b/tests/InputMethodStressTest/src/com/android/inputmethod/TestActivity.java new file mode 100644 index 0000000000000..7baf037e42158 --- /dev/null +++ b/tests/InputMethodStressTest/src/com/android/inputmethod/TestActivity.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.stresstest; + +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; + +import android.app.Activity; +import android.os.Bundle; +import android.view.WindowInsets; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.LinearLayout; + +import androidx.annotation.Nullable; + +public class TestActivity extends Activity { + + private EditText mEditText; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + 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); + } + + public boolean hasWindowFocus() { + return mEditText.hasWindowFocus(); + } + + public boolean isImeShown() { + WindowInsets insets = mEditText.getRootWindowInsets(); + return insets.isVisible(WindowInsets.Type.ime()); + } + + public void showIme() { + mEditText.requestFocus(); + InputMethodManager imm = getSystemService(InputMethodManager.class); + imm.showSoftInput(mEditText, 0); + } + + public void hideIme() { + InputMethodManager imm = getSystemService(InputMethodManager.class); + imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0); + } +}