summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java191
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/Android.bp3
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml2
-rw-r--r--services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java22
4 files changed, 199 insertions, 19 deletions
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index 16a98454d135..898658e759c0 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -24,6 +24,7 @@ import android.app.Instrumentation;
import android.content.Context;
import android.content.res.Configuration;
import android.os.RemoteException;
+import android.provider.Settings;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
@@ -31,7 +32,6 @@ import android.support.test.uiautomator.Until;
import android.util.Log;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
@@ -40,6 +40,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.apps.inputmethod.simpleime.ims.InputMethodServiceWrapper;
import com.android.apps.inputmethod.simpleime.testing.TestActivity;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -54,15 +55,19 @@ public class InputMethodServiceTest {
private static final String INPUT_METHOD_SERVICE_NAME = ".SimpleInputMethodService";
private static final String EDIT_TEXT_DESC = "Input box";
private static final long TIMEOUT_IN_SECONDS = 3;
-
- public Instrumentation mInstrumentation;
- public UiDevice mUiDevice;
- public Context mContext;
- public String mTargetPackageName;
- public TestActivity mActivity;
- public EditText mEditText;
- public InputMethodServiceWrapper mInputMethodService;
- public String mInputMethodId;
+ private static final String ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD =
+ "settings put secure show_ime_with_hard_keyboard 1";
+ private static final String DISABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD =
+ "settings put secure show_ime_with_hard_keyboard 0";
+
+ private Instrumentation mInstrumentation;
+ private UiDevice mUiDevice;
+ private Context mContext;
+ private String mTargetPackageName;
+ private TestActivity mActivity;
+ private InputMethodServiceWrapper mInputMethodService;
+ private String mInputMethodId;
+ private boolean mShowImeWithHardKeyboardEnabled;
@Before
public void setUp() throws Exception {
@@ -73,7 +78,9 @@ public class InputMethodServiceTest {
mInputMethodId = getInputMethodId();
prepareIme();
prepareEditor();
-
+ mInstrumentation.waitForIdleSync();
+ mUiDevice.freezeRotation();
+ mUiDevice.setOrientationNatural();
// Waits for input binding ready.
eventually(
() -> {
@@ -85,6 +92,28 @@ public class InputMethodServiceTest {
assertThat(mInputMethodService.getCurrentInputStarted()).isTrue();
assertThat(mInputMethodService.getCurrentInputViewStarted()).isFalse();
});
+ // Save the original value of show_ime_with_hard_keyboard in Settings.
+ mShowImeWithHardKeyboardEnabled = Settings.Secure.getInt(
+ mInputMethodService.getContentResolver(),
+ Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0;
+ // Disable showing Ime with hard keyboard because it is the precondition the for most test
+ // cases
+ if (mShowImeWithHardKeyboardEnabled) {
+ executeShellCommand(DISABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD);
+ }
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_NOKEYS;
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_YES;
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mUiDevice.unfreezeRotation();
+ executeShellCommand("ime disable " + mInputMethodId);
+ // Change back the original value of show_ime_with_hard_keyboard in Settings.
+ executeShellCommand(mShowImeWithHardKeyboardEnabled ? ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD
+ : DISABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD);
}
@Test
@@ -107,8 +136,6 @@ public class InputMethodServiceTest {
true /* inputViewStarted */);
// Triggers to hide IME via public API.
- // TODO(b/242838873): investigate why WIC#hide(ime()) does not work, likely related to
- // triggered from IME process.
verifyInputViewStatusOnMainSync(
() -> assertThat(mActivity.hideImeWithInputMethodManager(0 /* flags */)).isTrue(),
false /* inputViewStarted */);
@@ -145,6 +172,141 @@ public class InputMethodServiceTest {
false /* inputViewStarted */);
}
+ @Test
+ public void testOnEvaluateInputViewShown_showImeWithHardKeyboard() throws Exception {
+ executeShellCommand(ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD);
+ mInstrumentation.waitForIdleSync();
+
+ // Simulate connecting a hard keyboard
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_QWERTY;
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_NO;
+
+ eventually(() -> assertThat(mInputMethodService.onEvaluateInputViewShown()).isTrue());
+ }
+
+ @Test
+ public void testOnEvaluateInputViewShown_disableShowImeWithHardKeyboard() {
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_QWERTY;
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_NO;
+ eventually(() -> assertThat(mInputMethodService.onEvaluateInputViewShown()).isFalse());
+
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_NOKEYS;
+ eventually(() -> assertThat(mInputMethodService.onEvaluateInputViewShown()).isTrue());
+
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_QWERTY;
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_YES;
+ eventually(() -> assertThat(mInputMethodService.onEvaluateInputViewShown()).isTrue());
+ }
+
+ @Test
+ public void testShowSoftInput_disableShowImeWithHardKeyboard() throws Exception {
+ // Simulate connecting a hard keyboard
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_QWERTY;
+ mInputMethodService.getResources().getConfiguration().hardKeyboardHidden =
+ Configuration.HARDKEYBOARDHIDDEN_NO;
+ // When InputMethodService#onEvaluateInputViewShown() returns false, the Ime should not be
+ // shown no matter what the show flag is.
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(),
+ false /* inputViewStarted */);
+ verifyInputViewStatusOnMainSync(
+ () -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
+ false /* inputViewStarted */);
+ }
+
+ @Test
+ public void testShowSoftInputExplicitly() throws Exception {
+ // When InputMethodService#onEvaluateInputViewShown() returns true and flag is EXPLICIT, the
+ // Ime should be shown.
+ verifyInputViewStatusOnMainSync(
+ () -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
+ true /* inputViewStarted */);
+ }
+
+ @Test
+ public void testShowSoftInputImplicitly() throws Exception {
+ // When InputMethodService#onEvaluateInputViewShown() returns true and flag is IMPLICIT, the
+ // Ime should be shown.
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(),
+ true /* inputViewStarted */);
+ }
+
+ @Test
+ public void testShowSoftInputImplicitly_fullScreenMode() throws Exception {
+ // When keyboard is off, InputMethodService#onEvaluateInputViewShown returns true, flag is
+ // IMPLICIT and InputMethodService#onEvaluateFullScreenMode returns true, the Ime should not
+ // be shown.
+ setOrientation(2);
+ eventually(() -> assertThat(mUiDevice.isNaturalOrientation()).isFalse());
+ // Wait for the TestActivity to be recreated
+ eventually(() ->
+ assertThat(TestActivity.getLastCreatedInstance()).isNotEqualTo(mActivity));
+ // Get the new TestActivity
+ mActivity = TestActivity.getLastCreatedInstance();
+ assertThat(mActivity).isNotNull();
+ InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
+ // Wait for the new EditText to be served by InputMethodManager
+ eventually(() ->
+ assertThat(imm.hasActiveInputConnection(mActivity.getEditText())).isTrue());
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(),
+ false /* inputViewStarted */);
+ }
+
+ @Test
+ public void testShowSoftInputImplicitly_withHardKeyboard() throws Exception {
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_QWERTY;
+ // When connecting to a hard keyboard and the flag is IMPLICIT, the Ime should not be shown.
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(),
+ false /* inputViewStarted */);
+ }
+
+ @Test
+ public void testConfigurationChanged_withKeyboardShownExplicitly() throws InterruptedException {
+ verifyInputViewStatusOnMainSync(
+ () -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(),
+ true /* inputViewStarted */);
+ // Simulate a fake configuration change to avoid triggering the recreation of TestActivity.
+ mInputMethodService.getResources().getConfiguration().orientation =
+ Configuration.ORIENTATION_LANDSCAPE;
+ verifyInputViewStatusOnMainSync(() -> mInputMethodService.onConfigurationChanged(
+ mInputMethodService.getResources().getConfiguration()),
+ true /* inputViewStarted */);
+ }
+
+ @Test
+ public void testConfigurationChanged_withKeyboardShownImplicitly() throws InterruptedException {
+ verifyInputViewStatusOnMainSync(() -> assertThat(
+ mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(),
+ true /* inputViewStarted */);
+ // Simulate a fake configuration change to avoid triggering the recreation of TestActivity.
+ mInputMethodService.getResources().getConfiguration().orientation =
+ Configuration.ORIENTATION_LANDSCAPE;
+ mInputMethodService.getResources().getConfiguration().keyboard =
+ Configuration.KEYBOARD_QWERTY;
+
+ // Normally, IMS#onFinishInputView will be called when finishing the input view by the user.
+ // But if IMS#hideWindow is called when receiving a new configuration change, we don't
+ // expect that it's user-driven to finish the lifecycle of input view with
+ // IMS#onFinishInputView, because the input view will be re-initialized according to the
+ // last mShowSoftRequested state. So in this case we treat the input view is still alive.
+ verifyInputViewStatusOnMainSync(() -> mInputMethodService.onConfigurationChanged(
+ mInputMethodService.getResources().getConfiguration()),
+ true /* inputViewStarted */);
+ assertThat(mInputMethodService.isInputViewShown()).isFalse();
+ }
+
private void verifyInputViewStatus(Runnable runnable, boolean inputViewStarted)
throws InterruptedException {
verifyInputViewStatusInternal(runnable, inputViewStarted, false /*runOnMainSync*/);
@@ -184,8 +346,6 @@ public class InputMethodServiceTest {
Log.i(TAG, "Set orientation right");
verifyFullscreenMode(() -> setOrientation(2), false /* orientationPortrait */);
-
- mUiDevice.unfreezeRotation();
}
private void setOrientation(int orientation) {
@@ -249,7 +409,6 @@ public class InputMethodServiceTest {
private void prepareEditor() {
mActivity = TestActivity.start(mInstrumentation);
- mEditText = mActivity.mEditText;
Log.i(TAG, "Finish preparing activity with editor.");
}
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/Android.bp b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/Android.bp
index ef50476c2928..8d0e0c4260e8 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/Android.bp
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/Android.bp
@@ -58,5 +58,8 @@ android_library {
srcs: [
"src/com/android/apps/inputmethod/simpleime/testing/*.java",
],
+ static_libs: [
+ "androidx.annotation_annotation",
+ ],
sdk_version: "current",
}
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml
index 802caf132db5..996322de2c5e 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml
@@ -20,6 +20,8 @@
<uses-sdk android:targetSdkVersion="31" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+
<application android:debuggable="true"
android:label="@string/app_name">
<service
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java
index 0eec7e629d87..73b45019e311 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/testing/TestActivity.java
@@ -31,6 +31,10 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.LinearLayout;
+import androidx.annotation.Nullable;
+
+import java.lang.ref.WeakReference;
+
/**
* A special activity for testing purpose.
*
@@ -40,6 +44,8 @@ import android.widget.LinearLayout;
*/
public class TestActivity extends Activity {
private static final String TAG = "TestActivity";
+ private static WeakReference<TestActivity> sLastCreatedInstance =
+ new WeakReference<>(null);
/**
* Start a new test activity with an editor and wait for it to begin running before returning.
@@ -57,10 +63,15 @@ public class TestActivity extends Activity {
return (TestActivity) instrumentation.startActivitySync(intent);
}
- public EditText mEditText;
+ private EditText mEditText;
+
+ public EditText getEditText() {
+ return mEditText;
+ }
@Override
protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
LinearLayout rootView = new LinearLayout(this);
mEditText = new EditText(this);
@@ -68,14 +79,19 @@ public class TestActivity extends Activity {
rootView.addView(mEditText, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
setContentView(rootView);
mEditText.requestFocus();
- super.onCreate(savedInstanceState);
+ sLastCreatedInstance = new WeakReference<>(this);
+ }
+
+ /** Get the last created TestActivity instance. */
+ public static @Nullable TestActivity getLastCreatedInstance() {
+ return sLastCreatedInstance.get();
}
/** Shows soft keyboard via InputMethodManager. */
public boolean showImeWithInputMethodManager(int flags) {
InputMethodManager imm = getSystemService(InputMethodManager.class);
boolean result = imm.showSoftInput(mEditText, flags);
- Log.i(TAG, "hideIme() via InputMethodManager, result=" + result);
+ Log.i(TAG, "showIme() via InputMethodManager, result=" + result);
return result;
}