Index: content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java |
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java |
index bf4c10a3fb8dbd73e129020d4e867d539b0e9fea..fa0dd818f6784f23dcdb54caea584b1bc8870458 100644 |
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java |
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java |
@@ -29,25 +29,30 @@ import org.chromium.content.browser.test.util.TestInputMethodManagerWrapper; |
import org.chromium.content.browser.test.util.TestInputMethodManagerWrapper.Range; |
import org.chromium.content_public.browser.WebContents; |
import org.chromium.content_shell_apk.ContentShellTestBase; |
+import org.chromium.ui.base.ime.TextInputType; |
import java.util.ArrayList; |
+import java.util.Arrays; |
import java.util.List; |
+import java.util.concurrent.Callable; |
+import java.util.concurrent.ExecutionException; |
import java.util.concurrent.TimeoutException; |
/** |
* Integration tests for text input using cases based on fixed regressions. |
*/ |
public class ImeTest extends ContentShellTestBase { |
- |
private static final String DATA_URL = UrlUtils.encodeHtmlDataUri( |
"<html><head><meta name=\"viewport\"" |
+ "content=\"width=device-width, initial-scale=2.0, maximum-scale=2.0\" /></head>" |
+ "<body><form action=\"about:blank\">" |
- + "<input id=\"input_text\" type=\"text\" /><br/>" |
+ + "<input id=\"input_text\" type=\"text\" /><br/></form><form>" |
+ "<input id=\"input_radio\" type=\"radio\" style=\"width:50px;height:50px\" />" |
+ "<br/><textarea id=\"textarea\" rows=\"4\" cols=\"20\"></textarea>" |
+ "<br/><textarea id=\"textarea2\" rows=\"4\" cols=\"20\" autocomplete=\"off\">" |
+ "</textarea>" |
+ + "<br/><input id=\"input_number1\" type=\"number\" /><br/>" |
+ + "<br/><input id=\"input_number2\" type=\"number\" /><br/>" |
+ "<br/><p><span id=\"plain_text\">This is Plain Text One</span></p>" |
+ "</form></body></html>"); |
@@ -86,23 +91,21 @@ public class ImeTest extends ContentShellTestBase { |
mConnection = (TestAdapterInputConnection) getAdapterInputConnection(); |
mImeAdapter = getImeAdapter(); |
- // Two state updates from focus change and GestureTap. |
- waitAndVerifyStatesAndCalls(0, "", 0, 0, -1, -1); |
- waitAndVerifyStatesAndCalls(1, "", 0, 0, -1, -1); |
- |
- assertEquals(1, mInputMethodManagerWrapper.getShowSoftInputCounter()); |
+ waitAndVerifyStatesAndCalls("", 0, 0, -1, -1); |
+ waitForKeyboardStates(1, 0, 1, new Integer[] {TextInputType.TEXT}); |
assertEquals(0, mInputMethodManagerWrapper.getEditorInfo().initialSelStart); |
assertEquals(0, mInputMethodManagerWrapper.getEditorInfo().initialSelEnd); |
- resetUpdateStateList(); |
+ resetAllStates(); |
} |
- private void assertNoFurtherStateUpdate(final int index) throws InterruptedException { |
+ private void assertNoFurtherStateUpdate() throws InterruptedException { |
final List<TestImeState> states = mConnectionFactory.getImeStateList(); |
- assertFalse(CriteriaHelper.pollForCriteria(new Criteria() { |
+ final int oldSize = states.size(); |
+ assertFalse(CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
@Override |
public boolean isSatisfied() { |
- return states.size() > index; |
+ return states.size() > oldSize; |
} |
})); |
} |
@@ -110,51 +113,47 @@ public class ImeTest extends ContentShellTestBase { |
@MediumTest |
@Feature({"TextInput", "Main"}) |
public void testSetUpGeneratesNoFurtherStateUpdate() throws Throwable { |
- assertNoFurtherStateUpdate(0); |
+ assertNoFurtherStateUpdate(); |
+ waitForKeyboardStates(0, 0, 0, new Integer[] {}); |
} |
@MediumTest |
@Feature({"TextInput", "Main"}) |
public void testKeyboardDismissedAfterClickingGo() throws Throwable { |
setComposingText("hello", 1); |
- waitAndVerifyStatesAndCalls(0, "hello", 5, 5, 0, 5); |
+ waitAndVerifyStatesAndCalls("hello", 5, 5, 0, 5); |
performGo(mCallbackContainer); |
- waitAndVerifyStatesAndCalls(1, "", 0, 0, -1, -1); |
+ // May not have a selection update if initial selection was already 0,0. |
+ waitAndVerifyStates("", 0, 0, -1, -1); |
assertWaitForKeyboardStatus(false); |
} |
@SmallTest |
@Feature({"TextInput", "Main"}) |
- @RerunWithUpdatedContainerView |
- public void testGetTextUpdatesAfterEnteringText() throws Throwable { |
+ public void testCommitWhileComposingText() throws Throwable { |
setComposingText("h", 1); |
- waitAndVerifyStates(0, "h", 1, 1, 0, 1); |
- assertEquals(1, mInputMethodManagerWrapper.getShowSoftInputCounter()); |
+ waitAndVerifyStates("h", 1, 1, 0, 1); |
setComposingText("he", 1); |
- waitAndVerifyStates(1, "he", 2, 2, 0, 2); |
- assertEquals(1, mInputMethodManagerWrapper.getShowSoftInputCounter()); |
+ waitAndVerifyStates("he", 2, 2, 0, 2); |
setComposingText("hel", 1); |
- waitAndVerifyStates(2, "hel", 3, 3, 0, 3); |
- assertEquals(1, mInputMethodManagerWrapper.getShowSoftInputCounter()); |
+ waitAndVerifyStates("hel", 3, 3, 0, 3); |
commitText("hel", 1); |
- waitAndVerifyStates(3, "hel", 3, 3, -1, -1); |
- assertEquals(1, mInputMethodManagerWrapper.getShowSoftInputCounter()); |
+ waitAndVerifyStates("hel", 3, 3, -1, -1); |
} |
@SmallTest |
@Feature({"TextInput"}) |
- @RerunWithUpdatedContainerView |
public void testImeCopy() throws Exception { |
commitText("hello", 1); |
- waitAndVerifyStates(0, "hello", 5, 5, -1, -1); |
+ waitAndVerifyStates("hello", 5, 5, -1, -1); |
setSelection(2, 5); |
- waitAndVerifyStates(1, "hello", 2, 5, -1, -1); |
+ waitAndVerifyStates("hello", 2, 5, -1, -1); |
copy(); |
assertClipboardContents(getActivity(), "llo"); |
@@ -164,22 +163,90 @@ public class ImeTest extends ContentShellTestBase { |
@Feature({"TextInput"}) |
public void testEnterTextAndRefocus() throws Exception { |
commitText("hello", 1); |
- waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1); |
+ waitAndVerifyStatesAndCalls("hello", 5, 5, -1, -1); |
DOMUtils.clickNode(this, mContentViewCore, "input_radio"); |
assertWaitForKeyboardStatus(false); |
DOMUtils.clickNode(this, mContentViewCore, "input_text"); |
assertWaitForKeyboardStatus(true); |
- assertEquals(5, mInputMethodManagerWrapper.getEditorInfo().initialSelStart); |
- assertEquals(5, mInputMethodManagerWrapper.getEditorInfo().initialSelEnd); |
+ |
+ // Current logic does not set initial selection range correctly. If the |
+ // timing is correct (updateState immediately before restartInput happens). |
+ // assertEquals(5, mInputMethodManagerWrapper.getEditorInfo().initialSelStart); |
+ // assertEquals(5, mInputMethodManagerWrapper.getEditorInfo().initialSelEnd); |
+ waitAndVerifyStatesAndCalls("hello", 5, 5, -1, -1); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"TextInput"}) |
+ public void testShowAndHideSoftInput() throws Exception { |
+ focusElement("input_radio", false); |
+ waitAndVerifyStatesAndCalls("", 0, 0, -1, -1); |
+ |
+ // hideSoftKeyboard(). |
+ waitForKeyboardStates(0, 1, 0, new Integer[] {}); |
+ |
+ // showSoftInput(), restartInput() |
+ focusElement("input_number1"); |
+ waitForKeyboardStates(1, 1, 1, new Integer[] {TextInputType.NUMBER}); |
+ |
+ focusElement("input_number2"); |
+ // Hide should never be called here. Otherwise we will see a flicker. Restarted to |
+ // reset internal states to handle the new input form. |
+ waitForKeyboardStates(2, 1, 2, new Integer[] {TextInputType.NUMBER, TextInputType.NUMBER}); |
+ |
+ focusElement("input_text"); |
+ // showSoftInput() on input_text. restartInput() on input_number1 due to focus change, |
+ // and restartInput() on input_text later. |
+ // TODO(changwan): reduce unnecessary restart input. |
+ waitForKeyboardStates(3, 1, 4, new Integer[] { |
+ TextInputType.NUMBER, TextInputType.NUMBER, TextInputType.NUMBER, |
+ TextInputType.TEXT}); |
+ |
+ focusElement("input_radio", false); |
+ // hideSoftInput(). |
+ waitForKeyboardStates(3, 2, 4, new Integer[] { |
+ TextInputType.NUMBER, TextInputType.NUMBER, TextInputType.NUMBER, |
+ TextInputType.TEXT}); |
+ } |
+ |
+ private void waitForKeyboardStates(int show, int hide, int restart, Integer[] history) |
+ throws InterruptedException { |
+ final String expected = stringifyKeyboardStates(show, hide, restart, history); |
+ assertTrue("Expected: {" + expected + "}, Actual: {" + getKeyboardStates() + "}", |
+ CriteriaHelper.pollForCriteria(new Criteria() { |
+ @Override |
+ public boolean isSatisfied() { |
+ return expected.equals(getKeyboardStates()); |
+ } |
+ })); |
+ } |
+ |
+ private void resetAllStates() { |
+ mInputMethodManagerWrapper.resetCounters(); |
+ mConnectionFactory.clearTextInputTypeHistory(); |
+ resetUpdateStateList(); |
+ } |
+ |
+ private String getKeyboardStates() { |
+ int showCount = mInputMethodManagerWrapper.getShowSoftInputCounter(); |
+ int hideCount = mInputMethodManagerWrapper.getHideSoftInputCounter(); |
+ int restartCount = mInputMethodManagerWrapper.getRestartInputCounter(); |
+ Integer[] history = mConnectionFactory.getTextInputTypeHistory(); |
+ return stringifyKeyboardStates(showCount, hideCount, restartCount, history); |
+ } |
+ |
+ private String stringifyKeyboardStates(int show, int hide, int restart, Integer[] history) { |
+ return "show count: " + show + ", hide count: " + hide + ", restart count: " + restart |
+ + ", input type history: " + Arrays.deepToString(history); |
} |
@SmallTest |
@Feature({"TextInput"}) |
public void testKeyboardNotDismissedAfterCopySelection() throws Exception { |
commitText("Sample Text", 1); |
- waitAndVerifyStatesAndCalls(0, "Sample Text", 11, 11, -1, -1); |
+ waitAndVerifyStatesAndCalls("Sample Text", 11, 11, -1, -1); |
DOMUtils.clickNode(this, mContentViewCore, "input_text"); |
assertWaitForKeyboardStatus(true); |
DOMUtils.longPressNode(this, mContentViewCore, "input_text"); |
@@ -193,7 +260,7 @@ public class ImeTest extends ContentShellTestBase { |
@Feature({"TextInput"}) |
public void testImeNotDismissedAfterCutSelection() throws Exception { |
commitText("Sample Text", 1); |
- waitAndVerifyStatesAndCalls(0, "Sample Text", 11, 11, -1, -1); |
+ waitAndVerifyStatesAndCalls("Sample Text", 11, 11, -1, -1); |
DOMUtils.longPressNode(this, mContentViewCore, "input_text"); |
assertWaitForSelectActionBarStatus(true); |
assertWaitForKeyboardStatus(true); |
@@ -228,21 +295,21 @@ public class ImeTest extends ContentShellTestBase { |
public void testLongPressInputWhileComposingText() throws Exception { |
assertWaitForSelectActionBarStatus(false); |
setComposingText("Sample Text", 1); |
- waitAndVerifyStatesAndCalls(0, "Sample Text", 11, 11, 0, 11); |
+ waitAndVerifyStatesAndCalls("Sample Text", 11, 11, 0, 11); |
DOMUtils.longPressNode(this, mContentViewCore, "input_text"); |
assertWaitForSelectActionBarStatus(true); |
// Long press will first change selection region, and then trigger IME app to show up. |
// See RenderFrameImpl::didChangeSelection() and RenderWidget::didHandleGestureEvent(). |
- waitAndVerifyStatesAndCalls(1, "Sample Text", 7, 11, 0, 11); |
- waitAndVerifyStatesAndCalls(2, "Sample Text", 7, 11, 0, 11); |
+ waitAndVerifyStatesAndCalls("Sample Text", 7, 11, 0, 11); |
+ waitAndVerifyStatesAndCalls("Sample Text", 7, 11, 0, 11); |
// Now IME app wants to finish composing text because an external selection |
// change has been detected. At least Google Latin IME and Samsung IME |
// behave this way. |
finishComposingText(); |
- waitAndVerifyStatesAndCalls(3, "Sample Text", 7, 11, -1, -1); |
+ waitAndVerifyStatesAndCalls("Sample Text", 7, 11, -1, -1); |
} |
@SmallTest |
@@ -320,13 +387,13 @@ public class ImeTest extends ContentShellTestBase { |
@Feature({"TextInput"}) |
public void testImeCut() throws Exception { |
commitText("snarful", 1); |
- waitAndVerifyStatesAndCalls(0, "snarful", 7, 7, -1, -1); |
+ waitAndVerifyStatesAndCalls("snarful", 7, 7, -1, -1); |
setSelection(1, 5); |
- waitAndVerifyStatesAndCalls(1, "snarful", 1, 5, -1, -1); |
+ waitAndVerifyStatesAndCalls("snarful", 1, 5, -1, -1); |
cut(); |
- waitAndVerifyStatesAndCalls(2, "sul", 1, 1, -1, -1); |
+ waitAndVerifyStatesAndCalls("sul", 1, 1, -1, -1); |
assertClipboardContents(getActivity(), "narf"); |
} |
@@ -345,31 +412,29 @@ public class ImeTest extends ContentShellTestBase { |
}); |
paste(); |
- waitAndVerifyStatesAndCalls(0, "blarg", 5, 5, -1, -1); |
+ waitAndVerifyStatesAndCalls("blarg", 5, 5, -1, -1); |
setSelection(3, 5); |
- waitAndVerifyStatesAndCalls(1, "blarg", 3, 5, -1, -1); |
+ waitAndVerifyStatesAndCalls("blarg", 3, 5, -1, -1); |
paste(); |
- // Paste is a two step process when there is a non-zero selection. |
- waitAndVerifyStates(2, "bla", 3, 3, -1, -1); |
- waitAndVerifyStatesAndCalls(3, "blablarg", 8, 8, -1, -1); |
+ waitAndVerifyStatesAndCalls("blablarg", 8, 8, -1, -1); |
paste(); |
- waitAndVerifyStatesAndCalls(4, "blablargblarg", 13, 13, -1, -1); |
+ waitAndVerifyStatesAndCalls("blablargblarg", 13, 13, -1, -1); |
} |
@SmallTest |
@Feature({"TextInput"}) |
public void testImeSelectAndUnSelectAll() throws Exception { |
commitText("hello", 1); |
- waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1); |
+ waitAndVerifyStatesAndCalls("hello", 5, 5, -1, -1); |
selectAll(); |
- waitAndVerifyStatesAndCalls(1, "hello", 0, 5, -1, -1); |
+ waitAndVerifyStatesAndCalls("hello", 0, 5, -1, -1); |
unselect(); |
- waitAndVerifyStatesAndCalls(2, "", 0, 0, -1, -1); |
+ waitAndVerifyStatesAndCalls("", 0, 0, -1, -1); |
assertWaitForKeyboardStatus(false); |
} |
@@ -392,29 +457,29 @@ public class ImeTest extends ContentShellTestBase { |
focusElementAndWaitForStateUpdate("textarea"); |
commitText("hllo", 1); |
- waitAndVerifyStatesAndCalls(0, "hllo", 4, 4, -1, -1); |
+ waitAndVerifyStatesAndCalls("hllo", 4, 4, -1, -1); |
commitText(" ", 1); |
- waitAndVerifyStatesAndCalls(1, "hllo ", 5, 5, -1, -1); |
+ waitAndVerifyStatesAndCalls("hllo ", 5, 5, -1, -1); |
setSelection(1, 1); |
- waitAndVerifyStatesAndCalls(2, "hllo ", 1, 1, -1, -1); |
+ waitAndVerifyStatesAndCalls("hllo ", 1, 1, -1, -1); |
setComposingRegion(0, 4); |
- waitAndVerifyStatesAndCalls(3, "hllo ", 1, 1, 0, 4); |
+ waitAndVerifyStatesAndCalls("hllo ", 1, 1, 0, 4); |
finishComposingText(); |
- waitAndVerifyStatesAndCalls(4, "hllo ", 1, 1, -1, -1); |
+ waitAndVerifyStatesAndCalls("hllo ", 1, 1, -1, -1); |
commitText("\n", 1); |
- waitAndVerifyStatesAndCalls(5, "h\nllo ", 2, 2, -1, -1); |
+ waitAndVerifyStatesAndCalls("h\nllo ", 2, 2, -1, -1); |
} |
/* |
- @SmallTest |
- @Feature({"TextInput", "Main"}) |
http://crbug.com/445499 |
*/ |
+ @SmallTest |
+ @Feature({"TextInput", "Main"}) |
public void testDeleteText() throws Throwable { |
focusElement("textarea"); |
@@ -423,52 +488,47 @@ public class ImeTest extends ContentShellTestBase { |
// H |
resetUpdateStateList(); |
setComposingText("h", 1); |
- assertUpdateStateCall(1000); |
- assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("h", getTextBeforeCursor(9, 0)); |
// O |
resetUpdateStateList(); |
setComposingText("ho", 1); |
- assertUpdateStateCall(1000); |
- assertEquals("ho", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("ho", getTextBeforeCursor(9, 0)); |
resetUpdateStateList(); |
setComposingText("h", 1); |
- assertUpdateStateCall(1000); |
setComposingRegion(0, 1); |
setComposingText("h", 1); |
- assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("h", getTextBeforeCursor(9, 0)); |
// I |
setComposingText("hi", 1); |
- assertEquals("hi", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("hi", getTextBeforeCursor(9, 0)); |
// SPACE |
commitText("hi", 1); |
commitText(" ", 1); |
- assertEquals("hi ", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("hi ", getTextBeforeCursor(9, 0)); |
// DEL |
deleteSurroundingText(1, 0); |
setComposingRegion(0, 2); |
- assertEquals("hi", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("hi", getTextBeforeCursor(9, 0)); |
setComposingText("h", 1); |
- assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("h", getTextBeforeCursor(9, 0)); |
commitText("", 1); |
- assertEquals("", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("", getTextBeforeCursor(9, 0)); |
// DEL (on empty input) |
deleteSurroundingText(1, 0); // DEL on empty still sends 1,0 |
- assertEquals("", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("", getTextBeforeCursor(9, 0)); |
} |
- /* |
@SmallTest |
@Feature({"TextInput", "Main"}) |
- */ |
public void testSwipingText() throws Throwable { |
focusElement("textarea"); |
@@ -477,26 +537,20 @@ public class ImeTest extends ContentShellTestBase { |
// that the test reflects reality. If this test breaks, it's possible that code has |
// changed and different calls need to be made instead. |
// "three" |
- resetUpdateStateList(); |
setComposingText("three", 1); |
- assertUpdateStateCall(1000); |
- assertEquals("three", mConnection.getTextBeforeCursor(99, 0)); |
+ assertEquals("three", getTextBeforeCursor(99, 0)); |
// "word" |
commitText("three", 1); |
commitText(" ", 1); |
setComposingText("word", 1); |
- resetUpdateStateList(); |
- assertUpdateStateCall(1000); |
- assertEquals("three word", mConnection.getTextBeforeCursor(99, 0)); |
+ assertEquals("three word", getTextBeforeCursor(99, 0)); |
// "test" |
commitText("word", 1); |
commitText(" ", 1); |
- resetUpdateStateList(); |
setComposingText("test", 1); |
- assertUpdateStateCall(1000); |
- assertEquals("three word test", mConnection.getTextBeforeCursor(99, 0)); |
+ assertEquals("three word test", getTextBeforeCursor(99, 0)); |
} |
@SmallTest |
@@ -506,19 +560,19 @@ public class ImeTest extends ContentShellTestBase { |
final String smiley = "\uD83D\uDE0A"; |
commitText(smiley, 1); |
- waitAndVerifyStatesAndCalls(0, smiley, 2, 2, -1, -1); |
+ waitAndVerifyStatesAndCalls(smiley, 2, 2, -1, -1); |
// DEL, sent via dispatchKeyEvent like it is in Android WebView or a physical keyboard. |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)); |
- waitAndVerifyStatesAndCalls(1, "", 0, 0, -1, -1); |
+ waitAndVerifyStatesAndCalls("", 0, 0, -1, -1); |
// Make sure that we accept further typing after deleting the smiley. |
setComposingText("s", 1); |
- waitAndVerifyStatesAndCalls(2, "s", 1, 1, 0, 1); |
+ waitAndVerifyStatesAndCalls("s", 1, 1, 0, 1); |
setComposingText("sm", 1); |
- waitAndVerifyStatesAndCalls(3, "sm", 2, 2, 0, 2); |
+ waitAndVerifyStatesAndCalls("sm", 2, 2, 0, 2); |
} |
@SmallTest |
@@ -527,28 +581,19 @@ public class ImeTest extends ContentShellTestBase { |
focusElement("textarea"); |
// H |
- resetUpdateStateList(); |
commitText("h", 1); |
- assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); |
- assertUpdateStateCall(1000); |
- assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("h", getTextBeforeCursor(9, 0)); |
// O |
- resetUpdateStateList(); |
commitText("o", 1); |
- assertEquals("ho", mConnection.getTextBeforeCursor(9, 0)); |
- assertUpdateStateCall(1000); |
- assertEquals("ho", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("ho", getTextBeforeCursor(9, 0)); |
// DEL, sent via dispatchKeyEvent like it is in Android WebView or a physical keyboard. |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)); |
// DEL |
- resetUpdateStateList(); |
- assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); |
- assertUpdateStateCall(1000); |
- assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("h", getTextBeforeCursor(9, 0)); |
} |
@SmallTest |
@@ -557,18 +602,12 @@ public class ImeTest extends ContentShellTestBase { |
focusElement("textarea"); |
// H |
- resetUpdateStateList(); |
commitText("h", 1); |
- assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); |
- assertUpdateStateCall(1000); |
- assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("h", getTextBeforeCursor(9, 0)); |
// O |
- resetUpdateStateList(); |
commitText("o", 1); |
- assertEquals("ho", mConnection.getTextBeforeCursor(9, 0)); |
- assertUpdateStateCall(1000); |
- assertEquals("ho", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("ho", getTextBeforeCursor(9, 0)); |
// Multiple keydowns should each delete one character (this is for physical keyboard |
// key-repeat). |
@@ -577,10 +616,7 @@ public class ImeTest extends ContentShellTestBase { |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)); |
// DEL |
- resetUpdateStateList(); |
- assertEquals("", mConnection.getTextBeforeCursor(9, 0)); |
- assertUpdateStateCall(1000); |
- assertEquals("", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("", getTextBeforeCursor(9, 0)); |
} |
@SmallTest |
@@ -591,17 +627,17 @@ public class ImeTest extends ContentShellTestBase { |
// Type 'a' using a physical keyboard. |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A)); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_A)); |
- waitAndVerifyStatesAndCalls(0, "a", 1, 1, -1, -1); |
+ waitAndVerifyStatesAndCalls("a", 1, 1, -1, -1); |
// Type 'enter' key. |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER)); |
- waitAndVerifyStatesAndCalls(1, "a\n\n", 2, 2, -1, -1); |
+ waitAndVerifyStatesAndCalls("a\n\n", 2, 2, -1, -1); |
// Type 'b'. |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_B)); |
- waitAndVerifyStatesAndCalls(2, "a\nb", 3, 3, -1, -1); |
+ waitAndVerifyStatesAndCalls("a\nb", 3, 3, -1, -1); |
} |
@SmallTest |
@@ -612,72 +648,61 @@ public class ImeTest extends ContentShellTestBase { |
// h |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_H)); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_H)); |
- assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); |
- waitAndVerifyStatesAndCalls(0, "h", 1, 1, -1, -1); |
+ assertEquals("h", getTextBeforeCursor(9, 0)); |
+ waitAndVerifyStatesAndCalls("h", 1, 1, -1, -1); |
// ALT-i (circumflex accent key on virtual keyboard) |
dispatchKeyEvent(new KeyEvent( |
0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON)); |
- assertUpdateStateCall(1000); |
- assertEquals("hˆ", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("hˆ", getTextBeforeCursor(9, 0)); |
dispatchKeyEvent(new KeyEvent( |
0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON)); |
- assertEquals("hˆ", mConnection.getTextBeforeCursor(9, 0)); |
- waitAndVerifyStatesAndCalls(1, "hˆ", 2, 2, 1, 2); |
+ assertEquals("hˆ", getTextBeforeCursor(9, 0)); |
+ waitAndVerifyStatesAndCalls("hˆ", 2, 2, 1, 2); |
// o |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_O)); |
- assertUpdateStateCall(1000); |
- assertEquals("hô", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("hô", getTextBeforeCursor(9, 0)); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_O)); |
- assertEquals("hô", mConnection.getTextBeforeCursor(9, 0)); |
- waitAndVerifyStatesAndCalls(2, "hô", 2, 2, -1, -1); |
+ assertEquals("hô", getTextBeforeCursor(9, 0)); |
+ waitAndVerifyStatesAndCalls("hô", 2, 2, -1, -1); |
// ALT-i |
dispatchKeyEvent(new KeyEvent( |
0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON)); |
- assertUpdateStateCall(1000); |
dispatchKeyEvent(new KeyEvent( |
0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON)); |
- assertEquals("hôˆ", mConnection.getTextBeforeCursor(9, 0)); |
- waitAndVerifyStatesAndCalls(3, "hôˆ", 3, 3, 2, 3); |
+ assertEquals("hôˆ", getTextBeforeCursor(9, 0)); |
+ waitAndVerifyStatesAndCalls("hôˆ", 3, 3, 2, 3); |
// ALT-i again should have no effect |
dispatchKeyEvent(new KeyEvent( |
0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON)); |
- assertUpdateStateCall(1000); |
dispatchKeyEvent(new KeyEvent( |
0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON)); |
- assertEquals("hôˆ", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("hôˆ", getTextBeforeCursor(9, 0)); |
// b (cannot be accented, should just appear after) |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)); |
- assertUpdateStateCall(1000); |
- assertEquals("hôˆb", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("hôˆb", getTextBeforeCursor(9, 0)); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_B)); |
- assertEquals("hôˆb", mConnection.getTextBeforeCursor(9, 0)); |
- // A transitional state due to finishComposingText. |
- waitAndVerifyStates(4, "hôˆ", 3, 3, -1, -1); |
- waitAndVerifyStatesAndCalls(5, "hôˆb", 4, 4, -1, -1); |
+ assertEquals("hôˆb", getTextBeforeCursor(9, 0)); |
+ waitAndVerifyStatesAndCalls("hôˆb", 4, 4, -1, -1); |
// ALT-i |
dispatchKeyEvent(new KeyEvent( |
0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON)); |
- assertUpdateStateCall(1000); |
dispatchKeyEvent(new KeyEvent( |
0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON)); |
- assertEquals("hôˆbˆ", mConnection.getTextBeforeCursor(9, 0)); |
- waitAndVerifyStatesAndCalls(6, "hôˆbˆ", 5, 5, 4, 5); |
+ assertEquals("hôˆbˆ", getTextBeforeCursor(9, 0)); |
+ waitAndVerifyStatesAndCalls("hôˆbˆ", 5, 5, 4, 5); |
// Backspace |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); |
- assertUpdateStateCall(1000); |
- assertEquals("hôˆb", mConnection.getTextBeforeCursor(9, 0)); |
+ assertEquals("hôˆb", getTextBeforeCursor(9, 0)); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)); |
- assertEquals("hôˆb", mConnection.getTextBeforeCursor(9, 0)); |
- // A transitional state due to finishComposingText in deleteSurroundingTextImpl. |
- waitAndVerifyStates(7, "hôˆbˆ", 5, 5, -1, -1); |
- waitAndVerifyStatesAndCalls(8, "hôˆb", 4, 4, -1, -1); |
+ assertEquals("hôˆb", getTextBeforeCursor(9, 0)); |
+ waitAndVerifyStatesAndCalls("hôˆb", 4, 4, -1, -1); |
} |
@SmallTest |
@@ -697,17 +722,17 @@ public class ImeTest extends ContentShellTestBase { |
focusElementAndWaitForStateUpdate("textarea"); |
commitText("hello", 1); |
- waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1); |
+ waitAndVerifyStatesAndCalls("hello", 5, 5, -1, -1); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER)); |
// TODO(aurimas): remove this workaround when crbug.com/278584 is fixed. |
// The second new line is not a user visible/editable one, it is a side-effect of Blink |
// using <br> internally. This only happens when \n is at the end. |
- waitAndVerifyStatesAndCalls(1, "hello\n\n", 6, 6, -1, -1); |
+ waitAndVerifyStatesAndCalls("hello\n\n", 6, 6, -1, -1); |
commitText("world", 1); |
- waitAndVerifyStatesAndCalls(2, "hello\nworld", 11, 11, -1, -1); |
+ waitAndVerifyStatesAndCalls("hello\nworld", 11, 11, -1, -1); |
} |
@SmallTest |
@@ -716,20 +741,18 @@ public class ImeTest extends ContentShellTestBase { |
focusElementAndWaitForStateUpdate("textarea"); |
setComposingText("hello", 1); |
- waitAndVerifyStatesAndCalls(0, "hello", 5, 5, 0, 5); |
+ waitAndVerifyStatesAndCalls("hello", 5, 5, 0, 5); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER)); |
// TODO(aurimas): remove this workaround when crbug.com/278584 is fixed. |
- // A transitional state due to finishComposingText. |
- waitAndVerifyStates(1, "hello", 5, 5, -1, -1); |
// The second new line is not a user visible/editable one, it is a side-effect of Blink |
// using <br> internally. This only happens when \n is at the end. |
- waitAndVerifyStatesAndCalls(2, "hello\n\n", 6, 6, -1, -1); |
+ waitAndVerifyStatesAndCalls("hello\n\n", 6, 6, -1, -1); |
commitText("world", 1); |
- waitAndVerifyStatesAndCalls(3, "hello\nworld", 11, 11, -1, -1); |
+ waitAndVerifyStatesAndCalls("hello\nworld", 11, 11, -1, -1); |
} |
@SmallTest |
@@ -738,22 +761,21 @@ public class ImeTest extends ContentShellTestBase { |
focusElement("textarea"); |
// DPAD_CENTER should cause keyboard to appear |
- resetUpdateStateList(); |
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER)); |
- assertUpdateStateCall(1000); |
+ assertWaitForKeyboardStatus(true); |
} |
@SmallTest |
@Feature({"TextInput"}) |
public void testPastePopupShowAndHide() throws Throwable { |
commitText("hello", 1); |
- waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1); |
+ waitAndVerifyStatesAndCalls("hello", 5, 5, -1, -1); |
selectAll(); |
- waitAndVerifyStatesAndCalls(1, "hello", 0, 5, -1, -1); |
+ waitAndVerifyStatesAndCalls("hello", 0, 5, -1, -1); |
cut(); |
- waitAndVerifyStatesAndCalls(2, "", 0, 0, -1, -1); |
+ waitAndVerifyStatesAndCalls("", 0, 0, -1, -1); |
DOMUtils.longPressNode(this, mContentViewCore, "input_text"); |
assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
@@ -780,7 +802,7 @@ public class ImeTest extends ContentShellTestBase { |
@Feature({"TextInput"}) |
public void testSelectionClearedOnKeyEvent() throws Throwable { |
commitText("hello", 1); |
- waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1); |
+ waitAndVerifyStatesAndCalls("hello", 5, 5, -1, -1); |
DOMUtils.clickNode(this, mContentViewCore, "input_text"); |
assertWaitForKeyboardStatus(true); |
@@ -809,7 +831,7 @@ public class ImeTest extends ContentShellTestBase { |
@Feature({"TextInput"}) |
public void testRestartInputWhileComposingText() throws Throwable { |
setComposingText("abc", 1); |
- waitAndVerifyStatesAndCalls(0, "abc", 3, 3, 0, 3); |
+ waitAndVerifyStatesAndCalls("abc", 3, 3, 0, 3); |
ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
@Override |
public void run() { |
@@ -819,7 +841,7 @@ public class ImeTest extends ContentShellTestBase { |
// We don't do anything when input gets restarted. But we depend on Android's |
// InputMethodManager and/or input methods to call finishComposingText() in setting |
// current input connection as active or finishing the current input connection. |
- assertNoFurtherStateUpdate(1); |
+ assertNoFurtherStateUpdate(); |
} |
private void performGo(TestCallbackHelperContainer testCallbackHelperContainer) |
@@ -839,7 +861,7 @@ public class ImeTest extends ContentShellTestBase { |
assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
@Override |
public boolean isSatisfied() { |
- return show == getImeAdapter().mIsShowWithoutHideOutstanding |
+ return show == mInputMethodManagerWrapper.isShowWithoutHideOutstanding() |
&& (!show || getAdapterInputConnection() != null); |
} |
})); |
@@ -855,25 +877,32 @@ public class ImeTest extends ContentShellTestBase { |
})); |
} |
- private void waitAndVerifyStates(final int index, String text, final int selectionStart, |
- final int selectionEnd, final int compositionStart, final int compositionEnd) |
- throws InterruptedException { |
- final List<TestImeState> states = mConnectionFactory.getImeStateList(); |
- assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { |
- @Override |
- public boolean isSatisfied() { |
- return states.size() > index; |
- } |
- })); |
- states.get(index).assertEqualState( |
+ private void waitAndVerifyStates(String text, final int selectionStart, final int selectionEnd, |
+ final int compositionStart, final int compositionEnd) throws InterruptedException { |
+ final TestImeState expectedState = new TestImeState( |
text, selectionStart, selectionEnd, compositionStart, compositionEnd); |
+ assertTrue("Expected state: " + expectedState + ", actual state: " + getLastImeState(), |
+ CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
+ @Override |
+ public boolean isSatisfied() { |
+ final TestImeState lastState = getLastImeState(); |
+ if (lastState == null) return false; |
+ |
+ return expectedState.toString().equals(lastState.toString()); |
+ } |
+ })); |
} |
- private void waitAndVerifyStatesAndCalls(final int index, String text, final int selectionStart, |
+ private TestImeState getLastImeState() { |
+ final List<TestImeState> states = mConnectionFactory.getImeStateList(); |
+ if (states.isEmpty()) return null; |
+ return states.get(states.size() - 1); |
+ } |
+ |
+ private void waitAndVerifyStatesAndCalls(String text, final int selectionStart, |
final int selectionEnd, final int compositionStart, final int compositionEnd) |
throws InterruptedException { |
- waitAndVerifyStates( |
- index, text, selectionStart, selectionEnd, compositionStart, compositionEnd); |
+ waitAndVerifyStates(text, selectionStart, selectionEnd, compositionStart, compositionEnd); |
// Wait and verify calls to InputMethodManager. |
final Range selection = new Range(selectionStart, selectionEnd); |
@@ -881,7 +910,7 @@ public class ImeTest extends ContentShellTestBase { |
assertTrue("Actual selection was: " + mInputMethodManagerWrapper.getSelection() |
+ ", and actual composition was: " |
+ mInputMethodManagerWrapper.getComposition(), |
- CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
+ CriteriaHelper.pollForCriteria(new Criteria() { |
@Override |
public boolean isSatisfied() { |
return mInputMethodManagerWrapper.getSelection().equals(selection) |
@@ -894,18 +923,6 @@ public class ImeTest extends ContentShellTestBase { |
mConnectionFactory.getImeStateList().clear(); |
} |
- private void assertUpdateStateCall(int maxms) throws Exception { |
- while (mConnectionFactory.getImeStateList().size() == 0 && maxms > 0) { |
- try { |
- Thread.sleep(50); |
- } catch (Exception e) { |
- // Not really a problem since we're just going to sleep again. |
- } |
- maxms -= 50; |
- } |
- assertTrue(mConnectionFactory.getImeStateList().size() > 0); |
- } |
- |
private void assertClipboardContents(final Activity activity, final String expectedContents) |
throws InterruptedException { |
assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
@@ -1047,6 +1064,17 @@ public class ImeTest extends ContentShellTestBase { |
}); |
} |
+ private CharSequence getTextBeforeCursor(final int length, final int flags) |
+ throws ExecutionException { |
+ final AdapterInputConnection connection = mConnection; |
+ return ThreadUtils.runOnUiThreadBlocking(new Callable<CharSequence>() { |
+ @Override |
+ public CharSequence call() { |
+ return connection.getTextBeforeCursor(length, flags); |
+ } |
+ }); |
+ } |
+ |
/** |
* Focus element, wait for a single state update, reset state update list. |
* @param id ID of the element to focus. |
@@ -1054,13 +1082,18 @@ public class ImeTest extends ContentShellTestBase { |
private void focusElementAndWaitForStateUpdate(String id) |
throws InterruptedException, TimeoutException { |
focusElement(id); |
- waitAndVerifyStatesAndCalls(0, "", 0, 0, -1, -1); |
+ waitAndVerifyStatesAndCalls("", 0, 0, -1, -1); |
resetUpdateStateList(); |
} |
private void focusElement(final String id) throws InterruptedException, TimeoutException { |
+ focusElement(id, true); |
+ } |
+ |
+ private void focusElement(final String id, boolean shouldShowKeyboard) |
+ throws InterruptedException, TimeoutException { |
DOMUtils.focusNode(mWebContents, id); |
- assertWaitForKeyboardStatus(true); |
+ assertWaitForKeyboardStatus(shouldShowKeyboard); |
assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { |
@Override |
public boolean isSatisfied() { |
@@ -1078,10 +1111,12 @@ public class ImeTest extends ContentShellTestBase { |
private static class TestAdapterInputConnectionFactory extends |
ImeAdapter.AdapterInputConnectionFactory { |
private final List<TestImeState> mImeStateList = new ArrayList<>(); |
+ private final List<Integer> mTextInputTypeList = new ArrayList<>(); |
@Override |
public AdapterInputConnection get(View view, ImeAdapter imeAdapter, |
Editable editable, EditorInfo outAttrs) { |
+ mTextInputTypeList.add(imeAdapter.getTextInputType()); |
return new TestAdapterInputConnection( |
mImeStateList, view, imeAdapter, editable, outAttrs); |
} |
@@ -1089,6 +1124,16 @@ public class ImeTest extends ContentShellTestBase { |
public List<TestImeState> getImeStateList() { |
return mImeStateList; |
} |
+ |
+ public Integer[] getTextInputTypeHistory() { |
+ Integer[] result = new Integer[mTextInputTypeList.size()]; |
+ mTextInputTypeList.toArray(result); |
+ return result; |
+ } |
+ |
+ public void clearTextInputTypeHistory() { |
+ mTextInputTypeList.clear(); |
+ } |
} |
private static class TestAdapterInputConnection extends AdapterInputConnection { |
@@ -1126,13 +1171,10 @@ public class ImeTest extends ContentShellTestBase { |
mCompositionEnd = compositionEnd; |
} |
- public void assertEqualState(String text, int selectionStart, int selectionEnd, |
- int compositionStart, int compositionEnd) { |
- assertEquals("Text did not match", text, mText); |
- assertEquals("Selection start did not match", selectionStart, mSelectionStart); |
- assertEquals("Selection end did not match", selectionEnd, mSelectionEnd); |
- assertEquals("Composition start did not match", compositionStart, mCompositionStart); |
- assertEquals("Composition end did not match", compositionEnd, mCompositionEnd); |
+ @Override |
+ public String toString() { |
+ return "text: " + mText + ", selection: [" + mSelectionStart + ", " + mSelectionEnd |
+ + "], composition: [" + mCompositionStart + ", " + mCompositionEnd + "]"; |
} |
} |
} |