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; |
} |
} |
} |