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