| 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 704441b743a5ac6465a3e649ad94fb057d1d0aa8..cbfbde57c0e4981cdd2efb65be994e6862044586 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
|
| @@ -9,23 +9,26 @@ import android.content.ClipData;
|
| import android.content.ClipboardManager;
|
| import android.content.Context;
|
| import android.content.res.Configuration;
|
| +import android.os.Looper;
|
| import android.test.suitebuilder.annotation.MediumTest;
|
| import android.test.suitebuilder.annotation.SmallTest;
|
| import android.text.TextUtils;
|
| +import android.util.Pair;
|
| import android.view.KeyEvent;
|
| import android.view.View;
|
| import android.view.inputmethod.EditorInfo;
|
| +import android.view.inputmethod.InputConnection;
|
|
|
| import org.chromium.base.ThreadUtils;
|
| import org.chromium.base.test.util.Feature;
|
| import org.chromium.base.test.util.UrlUtils;
|
| import org.chromium.content.browser.ContentViewCore;
|
| +import org.chromium.content.browser.input.ChromiumBaseInputConnection.ThreadManager;
|
| import org.chromium.content.browser.test.util.Criteria;
|
| import org.chromium.content.browser.test.util.CriteriaHelper;
|
| import org.chromium.content.browser.test.util.DOMUtils;
|
| import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
|
| 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;
|
| @@ -55,8 +58,8 @@ public class ImeTest extends ContentShellTestBase {
|
| + "<br/><p><span id=\"plain_text\">This is Plain Text One</span></p>"
|
| + "</form></body></html>");
|
|
|
| - private TestAdapterInputConnection mConnection;
|
| - private TestAdapterInputConnectionFactory mConnectionFactory;
|
| + private ChromiumBaseInputConnection mConnection;
|
| + private TestInputConnectionFactory mConnectionFactory;
|
| private ImeAdapter mImeAdapter;
|
|
|
| private ContentViewCore mContentViewCore;
|
| @@ -76,7 +79,8 @@ public class ImeTest extends ContentShellTestBase {
|
| mInputMethodManagerWrapper = new TestInputMethodManagerWrapper(mContentViewCore);
|
| getImeAdapter().setInputMethodManagerWrapperForTest(mInputMethodManagerWrapper);
|
| assertEquals(0, mInputMethodManagerWrapper.getShowSoftInputCounter());
|
| - mConnectionFactory = new TestAdapterInputConnectionFactory();
|
| + mConnectionFactory = new TestInputConnectionFactory(
|
| + getImeAdapter().getInputConnectionFactoryForTest());
|
| getImeAdapter().setInputConnectionFactory(mConnectionFactory);
|
|
|
| mCallbackContainer = new TestCallbackHelperContainer(mContentViewCore);
|
| @@ -86,44 +90,22 @@ public class ImeTest extends ContentShellTestBase {
|
| DOMUtils.clickNode(this, mContentViewCore, "input_text");
|
| assertWaitForKeyboardStatus(true);
|
|
|
| - mConnection = (TestAdapterInputConnection) getAdapterInputConnection();
|
| + mConnection = getInputConnection();
|
| mImeAdapter = getImeAdapter();
|
|
|
| - waitAndVerifyStatesAndCalls(0, "", 0, 0, -1, -1);
|
| + waitAndVerifyUpdateSelection(0, 0, 0, -1, -1);
|
| waitForKeyboardStates(1, 0, 1, new Integer[] {TextInputType.TEXT});
|
| - assertEquals(0, mInputMethodManagerWrapper.getEditorInfo().initialSelStart);
|
| - assertEquals(0, mInputMethodManagerWrapper.getEditorInfo().initialSelEnd);
|
| + assertEquals(0, mConnectionFactory.getOutAttrs().initialSelStart);
|
| + assertEquals(0, mConnectionFactory.getOutAttrs().initialSelEnd);
|
|
|
| resetAllStates();
|
| }
|
|
|
| - private void assertNoFurtherStateUpdate(final int index) throws InterruptedException {
|
| - final List<TestImeState> states = mConnectionFactory.getImeStateList();
|
| - try {
|
| - CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
|
| - @Override
|
| - public boolean isSatisfied() {
|
| - return states.size() > index;
|
| - }
|
| - });
|
| - fail("Unexpected updates pending");
|
| - } catch (AssertionError e) {
|
| - // TODO(tedchoc): This is horrible and should never timeout to determine success.
|
| - }
|
| - }
|
| -
|
| - @MediumTest
|
| - @Feature({"TextInput", "Main"})
|
| - public void testSetUpGeneratesNoFurtherStateUpdate() throws Throwable {
|
| - assertNoFurtherStateUpdate(0);
|
| - 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);
|
| + waitAndVerifyUpdateSelection(0, 5, 5, 0, 5);
|
|
|
| performGo(mCallbackContainer);
|
|
|
| @@ -134,16 +116,24 @@ public class ImeTest extends ContentShellTestBase {
|
| @Feature({"TextInput", "Main"})
|
| public void testCommitWhileComposingText() throws Throwable {
|
| setComposingText("h", 1);
|
| - waitAndVerifyStates(0, "h", 1, 1, 0, 1);
|
| + waitAndVerifyUpdateSelection(0, 1, 1, 0, 1);
|
|
|
| setComposingText("he", 1);
|
| - waitAndVerifyStates(1, "he", 2, 2, 0, 2);
|
| + waitAndVerifyUpdateSelection(1, 2, 2, 0, 2);
|
|
|
| setComposingText("hel", 1);
|
| - waitAndVerifyStates(2, "hel", 3, 3, 0, 3);
|
| + waitAndVerifyUpdateSelection(2, 3, 3, 0, 3);
|
|
|
| commitText("hel", 1);
|
| - waitAndVerifyStates(3, "hel", 3, 3, -1, -1);
|
| + waitAndVerifyUpdateSelection(3, 3, 3, -1, -1);
|
| +
|
| + setComposingText("lo", 1);
|
| + waitAndVerifyUpdateSelection(4, 5, 5, 3, 5);
|
| +
|
| + commitText("", 1);
|
| + waitAndVerifyUpdateSelection(5, 3, 3, -1, -1);
|
| +
|
| + assertTextsAroundCursor("hel", "", "");
|
| }
|
|
|
| @SmallTest
|
| @@ -152,26 +142,28 @@ public class ImeTest extends ContentShellTestBase {
|
| focusElementAndWaitForStateUpdate("textarea");
|
|
|
| setComposingText("hello", 1);
|
| - waitAndVerifyStatesAndCalls(0, "hello", 5, 5, 0, 5);
|
| + waitAndVerifyUpdateSelection(0, 5, 5, 0, 5);
|
|
|
| // Cancel the current composition and replace it with enter.
|
| commitText("\n", 1);
|
| + waitAndVerifyUpdateSelection(1, 1, 1, -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(1, "\n\n", 1, 1, -1, -1);
|
| + assertTextsAroundCursor("\n", "", "\n");
|
|
|
| commitText("world", 1);
|
| - waitAndVerifyStatesAndCalls(2, "\nworld", 6, 6, -1, -1);
|
| + waitAndVerifyUpdateSelection(2, 6, 6, -1, -1);
|
| + assertTextsAroundCursor("\nworld", "", "");
|
| }
|
|
|
| @SmallTest
|
| @Feature({"TextInput"})
|
| public void testImeCopy() throws Exception {
|
| commitText("hello", 1);
|
| - waitAndVerifyStates(0, "hello", 5, 5, -1, -1);
|
| + waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
|
|
|
| setSelection(2, 5);
|
| - waitAndVerifyStates(1, "hello", 2, 5, -1, -1);
|
| + waitAndVerifyUpdateSelection(1, 2, 5, -1, -1);
|
|
|
| copy();
|
| assertClipboardContents(getActivity(), "llo");
|
| @@ -181,16 +173,13 @@ public class ImeTest extends ContentShellTestBase {
|
| @Feature({"TextInput"})
|
| public void testEnterTextAndRefocus() throws Exception {
|
| commitText("hello", 1);
|
| - waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1);
|
| -
|
| - DOMUtils.clickNode(this, mContentViewCore, "input_radio");
|
| - assertWaitForKeyboardStatus(false);
|
| -
|
| + waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
|
| + restartInput();
|
| DOMUtils.clickNode(this, mContentViewCore, "input_text");
|
| assertWaitForKeyboardStatus(true);
|
|
|
| - assertEquals(5, mInputMethodManagerWrapper.getEditorInfo().initialSelStart);
|
| - assertEquals(5, mInputMethodManagerWrapper.getEditorInfo().initialSelEnd);
|
| + assertEquals(5, mConnectionFactory.getOutAttrs().initialSelStart);
|
| + assertEquals(5, mConnectionFactory.getOutAttrs().initialSelEnd);
|
| }
|
|
|
| @SmallTest
|
| @@ -203,9 +192,14 @@ public class ImeTest extends ContentShellTestBase {
|
|
|
| // When input connection is null, we still need to set flags to prevent InputMethodService
|
| // from entering fullscreen mode and from opening custom UI.
|
| - assertNull(mInputMethodManagerWrapper.getInputConnection());
|
| - assertEquals(EditorInfo.IME_FLAG_NO_FULLSCREEN | EditorInfo.IME_FLAG_NO_EXTRACT_UI,
|
| - mInputMethodManagerWrapper.getEditorInfo().imeOptions);
|
| + CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
|
| + @Override
|
| + public boolean isSatisfied() {
|
| + return getInputConnection() == null;
|
| + }
|
| + });
|
| + assertTrue((mConnectionFactory.getOutAttrs().imeOptions
|
| + & (EditorInfo.IME_FLAG_NO_FULLSCREEN | EditorInfo.IME_FLAG_NO_EXTRACT_UI)) != 0);
|
|
|
| // showSoftInput(), restartInput()
|
| focusElement("input_number1");
|
| @@ -232,6 +226,27 @@ public class ImeTest extends ContentShellTestBase {
|
| TextInputType.TEXT});
|
| }
|
|
|
| + private void assertTextsAroundCursor(CharSequence before, CharSequence selected,
|
| + CharSequence after) {
|
| + assertEquals(before, getTextBeforeCursor(100, 0));
|
| +
|
| + CharSequence actualSelected = getSelectedText(0);
|
| + if (usingReplicaInputConnection() && TextUtils.isEmpty(actualSelected)) {
|
| + // ReplicaInputConnection will return null but ChromiumInputConnection will return "".
|
| + actualSelected = "";
|
| + }
|
| + assertEquals(selected, actualSelected);
|
| +
|
| + if (usingReplicaInputConnection() && after.equals("\n")) {
|
| + // When the text ends with \n, we have a second new line that is not user
|
| + // visible/editable one, it is a side effect of using <br> internally.
|
| + // Replica model simply deviates from the blink editor in this case.
|
| + assertEquals("", getTextAfterCursor(100, 0));
|
| + } else {
|
| + assertEquals(after, getTextAfterCursor(100, 0));
|
| + }
|
| + }
|
| +
|
| private void waitForKeyboardStates(int show, int hide, int restart, Integer[] history)
|
| throws InterruptedException {
|
| final String expected = stringifyKeyboardStates(show, hide, restart, history);
|
| @@ -246,27 +261,16 @@ public class ImeTest extends ContentShellTestBase {
|
| }
|
|
|
| private void resetAllStates() {
|
| - mInputMethodManagerWrapper.resetCounters();
|
| + mInputMethodManagerWrapper.reset();
|
| mConnectionFactory.clearTextInputTypeHistory();
|
| - resetUpdateStateList();
|
| }
|
|
|
| private String getKeyboardStates() {
|
| - try {
|
| - return ThreadUtils.runOnUiThreadBlocking(new Callable<String>() {
|
| - @Override
|
| - public String call() throws Exception {
|
| - int showCount = mInputMethodManagerWrapper.getShowSoftInputCounter();
|
| - int hideCount = mInputMethodManagerWrapper.getHideSoftInputCounter();
|
| - int restartCount = mInputMethodManagerWrapper.getRestartInputCounter();
|
| - Integer[] history = mConnectionFactory.getTextInputTypeHistory();
|
| - return stringifyKeyboardStates(showCount, hideCount, restartCount, history);
|
| - }
|
| - });
|
| - } catch (ExecutionException e) {
|
| - e.printStackTrace();
|
| - return null;
|
| - }
|
| + 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) {
|
| @@ -278,7 +282,7 @@ public class ImeTest extends ContentShellTestBase {
|
| @Feature({"TextInput"})
|
| public void testKeyboardNotDismissedAfterCopySelection() throws Exception {
|
| commitText("Sample Text", 1);
|
| - waitAndVerifyStatesAndCalls(0, "Sample Text", 11, 11, -1, -1);
|
| + waitAndVerifyUpdateSelection(0, 11, 11, -1, -1);
|
|
|
| // This will select 'Text' part.
|
| DOMUtils.clickNode(this, mContentViewCore, "input_text");
|
| @@ -299,7 +303,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);
|
| + waitAndVerifyUpdateSelection(0, 11, 11, -1, -1);
|
| DOMUtils.longPressNode(this, mContentViewCore, "input_text");
|
| assertWaitForSelectActionBarStatus(true);
|
| assertWaitForKeyboardStatus(true);
|
| @@ -334,20 +338,20 @@ public class ImeTest extends ContentShellTestBase {
|
| public void testLongPressInputWhileComposingText() throws Exception {
|
| assertWaitForSelectActionBarStatus(false);
|
| setComposingText("Sample Text", 1);
|
| - waitAndVerifyStatesAndCalls(0, "Sample Text", 11, 11, 0, 11);
|
| + waitAndVerifyUpdateSelection(0, 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);
|
| + waitAndVerifyUpdateSelection(1, 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(2, "Sample Text", 7, 11, -1, -1);
|
| + waitAndVerifyUpdateSelection(2, 7, 11, -1, -1);
|
| }
|
|
|
| @SmallTest
|
| @@ -493,14 +497,14 @@ public class ImeTest extends ContentShellTestBase {
|
| @Feature({"TextInput"})
|
| public void testImeCut() throws Exception {
|
| commitText("snarful", 1);
|
| - waitAndVerifyStatesAndCalls(0, "snarful", 7, 7, -1, -1);
|
| + waitAndVerifyUpdateSelection(0, 7, 7, -1, -1);
|
|
|
| setSelection(1, 5);
|
| - waitAndVerifyStatesAndCalls(1, "snarful", 1, 5, -1, -1);
|
| + waitAndVerifyUpdateSelection(1, 1, 5, -1, -1);
|
|
|
| cut();
|
| - waitAndVerifyStatesAndCalls(2, "sul", 1, 1, -1, -1);
|
| -
|
| + waitAndVerifyUpdateSelection(2, 1, 1, -1, -1);
|
| + assertTextsAroundCursor("s", "", "ul");
|
| assertClipboardContents(getActivity(), "narf");
|
| }
|
|
|
| @@ -518,28 +522,33 @@ public class ImeTest extends ContentShellTestBase {
|
| });
|
|
|
| paste();
|
| - waitAndVerifyStatesAndCalls(0, "blarg", 5, 5, -1, -1);
|
| + // Paste is a two step process when there is a non-zero selection.
|
| + waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
|
| + assertTextsAroundCursor("blarg", "", "");
|
|
|
| setSelection(3, 5);
|
| - waitAndVerifyStatesAndCalls(1, "blarg", 3, 5, -1, -1);
|
| + waitAndVerifyUpdateSelection(1, 3, 5, -1, -1);
|
| + assertTextsAroundCursor("bla", "rg", "");
|
|
|
| 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);
|
| + waitAndVerifyUpdateSelection(2, 3, 3, -1, -1);
|
| + waitAndVerifyUpdateSelection(3, 8, 8, -1, -1);
|
| + assertTextsAroundCursor("blablarg", "", "");
|
|
|
| paste();
|
| - waitAndVerifyStatesAndCalls(4, "blablargblarg", 13, 13, -1, -1);
|
| + waitAndVerifyUpdateSelection(4, 13, 13, -1, -1);
|
| + assertTextsAroundCursor("blablargblarg", "", "");
|
| }
|
|
|
| @SmallTest
|
| @Feature({"TextInput"})
|
| public void testImeSelectAndUnSelectAll() throws Exception {
|
| commitText("hello", 1);
|
| - waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1);
|
| + waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
|
|
|
| selectAll();
|
| - waitAndVerifyStatesAndCalls(1, "hello", 0, 5, -1, -1);
|
| + waitAndVerifyUpdateSelection(1, 0, 5, -1, -1);
|
|
|
| unselect();
|
|
|
| @@ -564,83 +573,75 @@ public class ImeTest extends ContentShellTestBase {
|
| focusElementAndWaitForStateUpdate("textarea");
|
|
|
| commitText("hllo", 1);
|
| - waitAndVerifyStatesAndCalls(0, "hllo", 4, 4, -1, -1);
|
| + waitAndVerifyUpdateSelection(0, 4, 4, -1, -1);
|
|
|
| commitText(" ", 1);
|
| - waitAndVerifyStatesAndCalls(1, "hllo ", 5, 5, -1, -1);
|
| + waitAndVerifyUpdateSelection(1, 5, 5, -1, -1);
|
|
|
| setSelection(1, 1);
|
| - waitAndVerifyStatesAndCalls(2, "hllo ", 1, 1, -1, -1);
|
| + waitAndVerifyUpdateSelection(2, 1, 1, -1, -1);
|
| + assertTextsAroundCursor("h", "", "llo ");
|
|
|
| setComposingRegion(0, 4);
|
| - waitAndVerifyStatesAndCalls(3, "hllo ", 1, 1, 0, 4);
|
| + waitAndVerifyUpdateSelection(3, 1, 1, 0, 4);
|
|
|
| finishComposingText();
|
| - waitAndVerifyStatesAndCalls(4, "hllo ", 1, 1, -1, -1);
|
| + waitAndVerifyUpdateSelection(4, 1, 1, -1, -1);
|
|
|
| commitText("\n", 1);
|
| - waitAndVerifyStatesAndCalls(5, "h\nllo ", 2, 2, -1, -1);
|
| + waitAndVerifyUpdateSelection(5, 2, 2, -1, -1);
|
| + assertTextsAroundCursor("h\n", "", "llo ");
|
| }
|
|
|
| - /*
|
| + // http://crbug.com/445499
|
| @SmallTest
|
| @Feature({"TextInput", "Main"})
|
| - http://crbug.com/445499
|
| - */
|
| public void testDeleteText() throws Throwable {
|
| focusElement("textarea");
|
|
|
| // The calls below are a reflection of what the stock Google Keyboard (Andr
|
| // when the noted key is touched on screen.
|
| // 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");
|
|
|
| @@ -649,26 +650,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
|
| @@ -678,19 +673,20 @@ public class ImeTest extends ContentShellTestBase {
|
| final String smiley = "\uD83D\uDE0A";
|
|
|
| commitText(smiley, 1);
|
| - waitAndVerifyStatesAndCalls(0, smiley, 2, 2, -1, -1);
|
| + waitAndVerifyUpdateSelection(0, 2, 2, -1, -1);
|
| + assertTextsAroundCursor(smiley, "", "");
|
|
|
| // 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);
|
| + waitAndVerifyUpdateSelection(1, 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);
|
| setComposingText("sm", 1);
|
| - waitAndVerifyStatesAndCalls(3, "sm", 2, 2, 0, 2);
|
| + waitAndVerifyUpdateSelection(2, 1, 1, 0, 1);
|
| + waitAndVerifyUpdateSelection(3, 2, 2, 0, 2);
|
| }
|
|
|
| @SmallTest
|
| @@ -699,28 +695,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
|
| @@ -729,18 +716,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).
|
| @@ -749,10 +730,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
|
| @@ -763,98 +741,102 @@ 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);
|
| + waitAndVerifyUpdateSelection(0, 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);
|
| + waitAndVerifyUpdateSelection(1, 2, 2, -1, -1);
|
| + assertTextsAroundCursor("a\n", "", "\n");
|
|
|
| // 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);
|
| + waitAndVerifyUpdateSelection(2, 3, 3, -1, -1);
|
| + assertTextsAroundCursor("a\nb", "", "");
|
| }
|
|
|
| @SmallTest
|
| @Feature({"TextInput", "Main"})
|
| public void testPhysicalKeyboard_AccentKeyCodes() throws Throwable {
|
| + if (!usingReplicaInputConnection()) {
|
| + // TODO(changwan): implement pending accents. AuraLinux uses GTK and ChromeOS uses
|
| + // CharacterComposer to combing a pending accent with the following key.
|
| + return;
|
| + }
|
| focusElementAndWaitForStateUpdate("textarea");
|
|
|
| // 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));
|
| + waitAndVerifyUpdateSelection(0, 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));
|
| + waitAndVerifyUpdateSelection(1, 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));
|
| + waitAndVerifyUpdateSelection(2, 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));
|
| + waitAndVerifyUpdateSelection(3, 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));
|
| + assertEquals("hôˆb", getTextBeforeCursor(9, 0));
|
| // A transitional state due to finishComposingText.
|
| - waitAndVerifyStates(4, "hôˆ", 3, 3, -1, -1);
|
| - waitAndVerifyStatesAndCalls(5, "hôˆb", 4, 4, -1, -1);
|
| + waitAndVerifyUpdateSelection(4, 3, 3, -1, -1);
|
| + waitAndVerifyUpdateSelection(5, 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));
|
| + waitAndVerifyUpdateSelection(6, 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));
|
| + assertEquals("hôˆb", 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);
|
| + waitAndVerifyUpdateSelection(7, 5, 5, -1, -1);
|
| + waitAndVerifyUpdateSelection(8, 4, 4, -1, -1);
|
| }
|
|
|
| @SmallTest
|
| @Feature({"TextInput", "Main"})
|
| public void testSetComposingRegionOutOfBounds() throws Throwable {
|
| + if (!usingReplicaInputConnection()) {
|
| + // TODO(changwan): fix this in webkit.
|
| + return;
|
| + }
|
| focusElement("textarea");
|
| setComposingText("hello", 1);
|
|
|
| @@ -869,17 +851,16 @@ public class ImeTest extends ContentShellTestBase {
|
| focusElementAndWaitForStateUpdate("textarea");
|
|
|
| commitText("hello", 1);
|
| - waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1);
|
| + waitAndVerifyUpdateSelection(0, 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);
|
| + waitAndVerifyUpdateSelection(1, 6, 6, -1, -1);
|
| + assertTextsAroundCursor("hello\n", "", "\n");
|
|
|
| commitText("world", 1);
|
| - waitAndVerifyStatesAndCalls(2, "hello\nworld", 11, 11, -1, -1);
|
| + waitAndVerifyUpdateSelection(2, 11, 11, -1, -1);
|
| + assertTextsAroundCursor("hello\nworld", "", "");
|
| }
|
|
|
| @SmallTest
|
| @@ -888,20 +869,22 @@ public class ImeTest extends ContentShellTestBase {
|
| focusElementAndWaitForStateUpdate("textarea");
|
|
|
| setComposingText("hello", 1);
|
| - waitAndVerifyStatesAndCalls(0, "hello", 5, 5, 0, 5);
|
| + waitAndVerifyUpdateSelection(0, 5, 5, 0, 5);
|
| +
|
| + // IME app should call this, otherwise enter key should clear the current composition.
|
| + finishComposingText();
|
| + waitAndVerifyUpdateSelection(1, 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.
|
| - // 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);
|
| + waitAndVerifyUpdateSelection(2, 6, 6, -1, -1);
|
|
|
| commitText("world", 1);
|
| - waitAndVerifyStatesAndCalls(3, "hello\nworld", 11, 11, -1, -1);
|
| + waitAndVerifyUpdateSelection(3, 11, 11, -1, -1);
|
| + assertTextsAroundCursor("hello\nworld", "", "");
|
| }
|
|
|
| @SmallTest
|
| @@ -910,9 +893,9 @@ 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);
|
| +
|
| + // TODO(changwan): should really check this.
|
| }
|
|
|
| @SmallTest
|
| @@ -921,21 +904,24 @@ public class ImeTest extends ContentShellTestBase {
|
| focusElementAndWaitForStateUpdate("textarea");
|
|
|
| commitText("hello", 1);
|
| - waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1);
|
| + waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
|
|
|
| dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT));
|
| dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_LEFT));
|
|
|
| - // Ideally getTextBeforeCursor immediately after dispatchKeyEvent should return a correct
|
| - // value, but we have a stop-gap solution in render_widget_input_handler and it make take
|
| - // some round trip time until we get the correct value.
|
| - // TODO(changwan): Change the test not to wait when we fix it.
|
| - waitUntilGetCharacterBeforeCursorBecomes("l");
|
| + if (usingReplicaInputConnection()) {
|
| + // Ideally getTextBeforeCursor immediately after dispatchKeyEvent should return a
|
| + // correct value, but we have a stop-gap solution in render_widget_input_handler and it
|
| + // make take some round trip time until we get the correct value.
|
| + waitUntilGetCharacterBeforeCursorBecomes("l");
|
| + } else {
|
| + assertTextsAroundCursor("hell", "", "o");
|
| + }
|
| }
|
|
|
| private void waitUntilGetCharacterBeforeCursorBecomes(final String expectedText)
|
| throws InterruptedException {
|
| - CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
|
| + pollForCriteriaOnThread(new Criteria() {
|
| @Override
|
| public boolean isSatisfied() {
|
| String actualText = (String) mConnection.getTextBeforeCursor(1, 0);
|
| @@ -945,17 +931,39 @@ public class ImeTest extends ContentShellTestBase {
|
| });
|
| }
|
|
|
| + private void pollForCriteriaOnThread(final Criteria criteria) throws InterruptedException {
|
| + CriteriaHelper.pollForCriteria(new Criteria() {
|
| + @Override
|
| + public boolean isSatisfied() {
|
| + return mConnectionFactory.getThreadManager().runBlockingForTesting(
|
| + new Callable<Boolean>() {
|
| + @Override
|
| + public Boolean call() throws Exception {
|
| + return criteria.isSatisfied();
|
| + }
|
| + });
|
| + }
|
| +
|
| + @Override
|
| + public String getFailureReason() {
|
| + return criteria.getFailureReason();
|
| + }
|
| + });
|
| + }
|
| +
|
| @SmallTest
|
| @Feature({"TextInput"})
|
| public void testPastePopupShowAndHide() throws Throwable {
|
| commitText("hello", 1);
|
| - waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1);
|
| + waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
|
|
|
| selectAll();
|
| - waitAndVerifyStatesAndCalls(1, "hello", 0, 5, -1, -1);
|
| + waitAndVerifyUpdateSelection(1, 0, 5, -1, -1);
|
| + assertTextsAroundCursor("", "hello", "");
|
|
|
| cut();
|
| - waitAndVerifyStatesAndCalls(2, "", 0, 0, -1, -1);
|
| + waitAndVerifyUpdateSelection(2, 0, 0, -1, -1);
|
| + assertTextsAroundCursor("", "", "");
|
|
|
| DOMUtils.longPressNode(this, mContentViewCore, "input_text");
|
| CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
|
| @@ -982,7 +990,7 @@ public class ImeTest extends ContentShellTestBase {
|
| @Feature({"TextInput"})
|
| public void testSelectionClearedOnKeyEvent() throws Throwable {
|
| commitText("hello", 1);
|
| - waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1);
|
| + waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
|
|
|
| DOMUtils.clickNode(this, mContentViewCore, "input_text");
|
| assertWaitForKeyboardStatus(true);
|
| @@ -1012,28 +1020,40 @@ public class ImeTest extends ContentShellTestBase {
|
| @Feature({"TextInput"})
|
| public void testRestartInputWhileComposingText() throws Throwable {
|
| setComposingText("abc", 1);
|
| - waitAndVerifyStatesAndCalls(0, "abc", 3, 3, 0, 3);
|
| - ThreadUtils.runOnUiThreadBlocking(new Runnable() {
|
| - @Override
|
| - public void run() {
|
| - mImeAdapter.restartInput();
|
| - }
|
| - });
|
| + waitAndVerifyUpdateSelection(0, 3, 3, 0, 3);
|
| + restartInput();
|
| // 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);
|
| + Thread.sleep(1000);
|
| + assertEquals(1, mInputMethodManagerWrapper.getUpdateSelectionList().size());
|
| + }
|
| +
|
| + @MediumTest
|
| + @Feature({"TextInput"})
|
| + public void testRestartInputKeepsTextAndCursor() throws Exception {
|
| + commitText("ab", 2);
|
| + restartInput();
|
| + assertEquals("ab", getTextBeforeCursor(10, 0));
|
| }
|
|
|
| private void performGo(TestCallbackHelperContainer testCallbackHelperContainer)
|
| throws Throwable {
|
| - final AdapterInputConnection inputConnection = mConnection;
|
| + final InputConnection inputConnection = mConnection;
|
| + final Callable<Void> callable = new Callable<Void>() {
|
| + @Override
|
| + public Void call() throws Exception {
|
| + inputConnection.performEditorAction(EditorInfo.IME_ACTION_GO);
|
| + return null;
|
| + }
|
| + };
|
| +
|
| handleBlockingCallbackAction(
|
| testCallbackHelperContainer.getOnPageFinishedHelper(),
|
| new Runnable() {
|
| @Override
|
| public void run() {
|
| - inputConnection.performEditorAction(EditorInfo.IME_ACTION_GO);
|
| + mConnectionFactory.getThreadManager().runBlockingForTesting(callable);
|
| }
|
| });
|
| }
|
| @@ -1045,7 +1065,7 @@ public class ImeTest extends ContentShellTestBase {
|
| // We do not check the other way around: in some cases we need to keep
|
| // input connection even when the last known status is 'hidden'.
|
| // See crbug.com/569332 for more details.
|
| - if (show && getAdapterInputConnection() == null) {
|
| + if (show && getInputConnection() == null) {
|
| updateFailureReason("input connection should not be null.");
|
| return false;
|
| }
|
| @@ -1065,56 +1085,25 @@ public class ImeTest extends ContentShellTestBase {
|
| });
|
| }
|
|
|
| - private void waitAndVerifyStates(final int index, String text, final int selectionStart,
|
| + private void waitAndVerifyUpdateSelection(final int index, final int selectionStart,
|
| final int selectionEnd, final int compositionStart, final int compositionEnd)
|
| throws InterruptedException {
|
| - final List<TestImeState> states = mConnectionFactory.getImeStateList();
|
| + final List<Pair<Range, Range>> states = mInputMethodManagerWrapper.getUpdateSelectionList();
|
| CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
|
| @Override
|
| public boolean isSatisfied() {
|
| return states.size() > index;
|
| }
|
| });
|
| - states.get(index).assertEqualState(
|
| - text, selectionStart, selectionEnd, compositionStart, compositionEnd);
|
| + Pair<Range, Range> selection = states.get(index);
|
| + assertEquals(selectionStart, selection.first.start());
|
| + assertEquals(selectionEnd, selection.first.end());
|
| + assertEquals(compositionStart, selection.second.start());
|
| + assertEquals(compositionEnd, selection.second.end());
|
| }
|
|
|
| - private void waitAndVerifyStatesAndCalls(final int index, String text, final int selectionStart,
|
| - final int selectionEnd, final int compositionStart, final int compositionEnd)
|
| - throws InterruptedException {
|
| - waitAndVerifyStates(
|
| - index, text, selectionStart, selectionEnd, compositionStart, compositionEnd);
|
| -
|
| - // Wait and verify calls to InputMethodManager.
|
| - final Range selection = new Range(selectionStart, selectionEnd);
|
| - final Range composition = new Range(compositionStart, compositionEnd);
|
| - CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
|
| - @Override
|
| - public boolean isSatisfied() {
|
| - updateFailureReason(
|
| - "Actual selection was: " + mInputMethodManagerWrapper.getSelection()
|
| - + ", and actual composition was: "
|
| - + mInputMethodManagerWrapper.getComposition());
|
| - return mInputMethodManagerWrapper.getSelection().equals(selection)
|
| - && mInputMethodManagerWrapper.getComposition().equals(composition);
|
| - }
|
| - });
|
| - }
|
| -
|
| - private void resetUpdateStateList() {
|
| - 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 resetUpdateSelectionList() {
|
| + mInputMethodManagerWrapper.getUpdateSelectionList().clear();
|
| }
|
|
|
| private void assertClipboardContents(final Activity activity, final String expectedContents)
|
| @@ -1135,8 +1124,28 @@ public class ImeTest extends ContentShellTestBase {
|
| return mContentViewCore.getImeAdapterForTest();
|
| }
|
|
|
| - private AdapterInputConnection getAdapterInputConnection() {
|
| - return mContentViewCore.getImeAdapterForTest().getInputConnectionForTest();
|
| + private ChromiumBaseInputConnection getInputConnection() {
|
| + try {
|
| + return ThreadUtils.runOnUiThreadBlocking(new Callable<ChromiumBaseInputConnection>() {
|
| + @Override
|
| + public ChromiumBaseInputConnection call() {
|
| + return mContentViewCore.getImeAdapterForTest().getInputConnectionForTest();
|
| + }
|
| + });
|
| + } catch (ExecutionException e) {
|
| + e.printStackTrace();
|
| + fail();
|
| + return null;
|
| + }
|
| + }
|
| +
|
| + private void restartInput() {
|
| + ThreadUtils.runOnUiThreadBlocking(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + mImeAdapter.restartInput();
|
| + }
|
| + });
|
| }
|
|
|
| private void copy() {
|
| @@ -1189,66 +1198,99 @@ public class ImeTest extends ContentShellTestBase {
|
| });
|
| }
|
|
|
| - private void commitText(final CharSequence text, final int newCursorPosition) {
|
| - final AdapterInputConnection connection = mConnection;
|
| - ThreadUtils.runOnUiThreadBlocking(new Runnable() {
|
| + private boolean commitText(final CharSequence text, final int newCursorPosition) {
|
| + final ChromiumBaseInputConnection connection = mConnection;
|
| + return mConnectionFactory.getThreadManager().runBlockingForTesting(new Callable<Boolean>() {
|
| @Override
|
| - public void run() {
|
| - connection.commitText(text, newCursorPosition);
|
| + public Boolean call() {
|
| + return connection.commitText(text, newCursorPosition);
|
| }
|
| });
|
| }
|
|
|
| - private void setSelection(final int start, final int end) {
|
| - final AdapterInputConnection connection = mConnection;
|
| - ThreadUtils.runOnUiThreadBlocking(new Runnable() {
|
| + private boolean setSelection(final int start, final int end) {
|
| + final ChromiumBaseInputConnection connection = mConnection;
|
| + return mConnectionFactory.getThreadManager().runBlockingForTesting(new Callable<Boolean>() {
|
| @Override
|
| - public void run() {
|
| - connection.setSelection(start, end);
|
| + public Boolean call() {
|
| + return connection.setSelection(start, end);
|
| }
|
| });
|
| }
|
|
|
| - private void setComposingRegion(final int start, final int end) {
|
| - final AdapterInputConnection connection = mConnection;
|
| - ThreadUtils.runOnUiThreadBlocking(new Runnable() {
|
| + private boolean setComposingRegion(final int start, final int end) {
|
| + final ChromiumBaseInputConnection connection = mConnection;
|
| + return mConnectionFactory.getThreadManager().runBlockingForTesting(new Callable<Boolean>() {
|
| @Override
|
| - public void run() {
|
| - connection.setComposingRegion(start, end);
|
| + public Boolean call() {
|
| + return connection.setComposingRegion(start, end);
|
| }
|
| });
|
| }
|
|
|
| - private void setComposingText(final CharSequence text, final int newCursorPosition) {
|
| - final AdapterInputConnection connection = mConnection;
|
| - ThreadUtils.runOnUiThreadBlocking(new Runnable() {
|
| + private boolean setComposingText(final CharSequence text, final int newCursorPosition) {
|
| + final ChromiumBaseInputConnection connection = mConnection;
|
| + return mConnectionFactory.getThreadManager().runBlockingForTesting(new Callable<Boolean>() {
|
| @Override
|
| - public void run() {
|
| - connection.setComposingText(text, newCursorPosition);
|
| + public Boolean call() {
|
| + return connection.setComposingText(text, newCursorPosition);
|
| }
|
| });
|
| }
|
|
|
| - private void finishComposingText() {
|
| - final AdapterInputConnection connection = mConnection;
|
| - ThreadUtils.runOnUiThreadBlocking(new Runnable() {
|
| + private boolean finishComposingText() {
|
| + final ChromiumBaseInputConnection connection = mConnection;
|
| + return mConnectionFactory.getThreadManager().runBlockingForTesting(new Callable<Boolean>() {
|
| @Override
|
| - public void run() {
|
| - connection.finishComposingText();
|
| + public Boolean call() {
|
| + return connection.finishComposingText();
|
| }
|
| });
|
| }
|
|
|
| - private void deleteSurroundingText(final int before, final int after) {
|
| - final AdapterInputConnection connection = mConnection;
|
| - ThreadUtils.runOnUiThreadBlocking(new Runnable() {
|
| + private boolean deleteSurroundingText(final int before, final int after) {
|
| + final ChromiumBaseInputConnection connection = mConnection;
|
| + return mConnectionFactory.getThreadManager().runBlockingForTesting(new Callable<Boolean>() {
|
| @Override
|
| - public void run() {
|
| - connection.deleteSurroundingText(before, after);
|
| + public Boolean call() {
|
| + return connection.deleteSurroundingText(before, after);
|
| }
|
| });
|
| }
|
|
|
| + private CharSequence getTextBeforeCursor(final int length, final int flags) {
|
| + final ChromiumBaseInputConnection connection = mConnection;
|
| + return mConnectionFactory.getThreadManager().runBlockingForTesting(
|
| + new Callable<CharSequence>() {
|
| + @Override
|
| + public CharSequence call() {
|
| + return connection.getTextBeforeCursor(length, flags);
|
| + }
|
| + });
|
| + }
|
| +
|
| + private CharSequence getSelectedText(final int flags) {
|
| + final ChromiumBaseInputConnection connection = mConnection;
|
| + return mConnectionFactory.getThreadManager().runBlockingForTesting(
|
| + new Callable<CharSequence>() {
|
| + @Override
|
| + public CharSequence call() {
|
| + return connection.getSelectedText(flags);
|
| + }
|
| + });
|
| + }
|
| +
|
| + private CharSequence getTextAfterCursor(final int length, final int flags) {
|
| + final ChromiumBaseInputConnection connection = mConnection;
|
| + return mConnectionFactory.getThreadManager().runBlockingForTesting(
|
| + new Callable<CharSequence>() {
|
| + @Override
|
| + public CharSequence call() {
|
| + return connection.getTextAfterCursor(length, flags);
|
| + }
|
| + });
|
| + }
|
| +
|
| private void dispatchKeyEvent(final KeyEvent event) {
|
| ThreadUtils.runOnUiThreadBlocking(new Runnable() {
|
| @Override
|
| @@ -1265,8 +1307,8 @@ public class ImeTest extends ContentShellTestBase {
|
| private void focusElementAndWaitForStateUpdate(String id)
|
| throws InterruptedException, TimeoutException {
|
| focusElement(id);
|
| - waitAndVerifyStatesAndCalls(0, "", 0, 0, -1, -1);
|
| - resetUpdateStateList();
|
| + waitAndVerifyUpdateSelection(0, 0, 0, -1, -1);
|
| + resetUpdateSelectionList();
|
| }
|
|
|
| private void focusElement(final String id) throws InterruptedException, TimeoutException {
|
| @@ -1288,24 +1330,35 @@ public class ImeTest extends ContentShellTestBase {
|
| }
|
| });
|
| // When we focus another element, the connection may be recreated.
|
| - mConnection = (TestAdapterInputConnection) getAdapterInputConnection();
|
| + mConnection = getInputConnection();
|
| }
|
|
|
| - private static class TestAdapterInputConnectionFactory extends
|
| - ImeAdapter.AdapterInputConnectionFactory {
|
| - private final List<TestImeState> mImeStateList = new ArrayList<>();
|
| + private boolean usingReplicaInputConnection() {
|
| + return mConnectionFactory.getThreadManager().getHandler().getLooper()
|
| + == Looper.getMainLooper();
|
| + }
|
| +
|
| + private static class TestInputConnectionFactory implements ChromiumBaseInputConnection.Factory {
|
| + private final ChromiumBaseInputConnection.Factory mFactory;
|
| +
|
| private final List<Integer> mTextInputTypeList = new ArrayList<>();
|
| + private EditorInfo mOutAttrs;
|
| +
|
| + public TestInputConnectionFactory(ChromiumBaseInputConnection.Factory factory) {
|
| + mFactory = factory;
|
| + }
|
|
|
| @Override
|
| - public AdapterInputConnection get(View view, ImeAdapter imeAdapter, int initialSelStart,
|
| - int initialSelEnd, EditorInfo outAttrs) {
|
| - mTextInputTypeList.add(imeAdapter.getTextInputType());
|
| - return new TestAdapterInputConnection(
|
| - mImeStateList, view, imeAdapter, initialSelStart, initialSelEnd, outAttrs);
|
| + public ChromiumBaseInputConnection initializeAndGet(View view, ImeAdapter imeAdapter,
|
| + int inputType, int inputFlags, EditorInfo outAttrs) {
|
| + mTextInputTypeList.add(inputType);
|
| + mOutAttrs = outAttrs;
|
| + return mFactory.initializeAndGet(view, imeAdapter, inputType, inputFlags, outAttrs);
|
| }
|
|
|
| - public List<TestImeState> getImeStateList() {
|
| - return mImeStateList;
|
| + @Override
|
| + public ThreadManager getThreadManager() {
|
| + return mFactory.getThreadManager();
|
| }
|
|
|
| public Integer[] getTextInputTypeHistory() {
|
| @@ -1317,51 +1370,9 @@ public class ImeTest extends ContentShellTestBase {
|
| public void clearTextInputTypeHistory() {
|
| mTextInputTypeList.clear();
|
| }
|
| - }
|
| -
|
| - private static class TestAdapterInputConnection extends AdapterInputConnection {
|
| - private final List<TestImeState> mImeStateList;
|
| -
|
| - public TestAdapterInputConnection(List<TestImeState> imeStateList, View view,
|
| - ImeAdapter imeAdapter, int initialSelStart, int initialSelEnd,
|
| - EditorInfo outAttrs) {
|
| - super(view, imeAdapter, initialSelStart, initialSelEnd, outAttrs);
|
| - mImeStateList = imeStateList;
|
| - }
|
| -
|
| - @Override
|
| - public void updateState(String text, int selectionStart, int selectionEnd,
|
| - int compositionStart, int compositionEnd, boolean requiredAck) {
|
| - mImeStateList.add(new TestImeState(
|
| - text, selectionStart, selectionEnd, compositionStart, compositionEnd));
|
| - super.updateState(text, selectionStart, selectionEnd, compositionStart,
|
| - compositionEnd, requiredAck);
|
| - }
|
| - }
|
| -
|
| - private static class TestImeState {
|
| - private final String mText;
|
| - private final int mSelectionStart;
|
| - private final int mSelectionEnd;
|
| - private final int mCompositionStart;
|
| - private final int mCompositionEnd;
|
| -
|
| - public TestImeState(String text, int selectionStart, int selectionEnd,
|
| - int compositionStart, int compositionEnd) {
|
| - mText = text;
|
| - mSelectionStart = selectionStart;
|
| - mSelectionEnd = selectionEnd;
|
| - mCompositionStart = compositionStart;
|
| - 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);
|
| + public EditorInfo getOutAttrs() {
|
| + return mOutAttrs;
|
| }
|
| }
|
| }
|
|
|