Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(240)

Side by Side Diff: content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java

Issue 1278593004: Introduce ThreadedInputConnection behind a switch (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased and added a TODO for test Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.content.browser.input; 5 package org.chromium.content.browser.input;
6 6
7 import android.app.Activity; 7 import android.app.Activity;
8 import android.content.ClipData; 8 import android.content.ClipData;
9 import android.content.ClipboardManager; 9 import android.content.ClipboardManager;
10 import android.content.Context; 10 import android.content.Context;
11 import android.content.res.Configuration; 11 import android.content.res.Configuration;
12 import android.os.Handler;
13 import android.os.Looper;
12 import android.test.suitebuilder.annotation.MediumTest; 14 import android.test.suitebuilder.annotation.MediumTest;
13 import android.test.suitebuilder.annotation.SmallTest; 15 import android.test.suitebuilder.annotation.SmallTest;
14 import android.text.TextUtils; 16 import android.text.TextUtils;
17 import android.util.Pair;
15 import android.view.KeyEvent; 18 import android.view.KeyEvent;
16 import android.view.View; 19 import android.view.View;
17 import android.view.inputmethod.EditorInfo; 20 import android.view.inputmethod.EditorInfo;
21 import android.view.inputmethod.InputConnection;
18 22
23 import org.chromium.base.ObserverList;
19 import org.chromium.base.ThreadUtils; 24 import org.chromium.base.ThreadUtils;
20 import org.chromium.base.test.util.Feature; 25 import org.chromium.base.test.util.Feature;
21 import org.chromium.base.test.util.UrlUtils; 26 import org.chromium.base.test.util.UrlUtils;
22 import org.chromium.content.browser.ContentViewCore; 27 import org.chromium.content.browser.ContentViewCore;
23 import org.chromium.content.browser.test.util.Criteria; 28 import org.chromium.content.browser.test.util.Criteria;
24 import org.chromium.content.browser.test.util.CriteriaHelper; 29 import org.chromium.content.browser.test.util.CriteriaHelper;
25 import org.chromium.content.browser.test.util.DOMUtils; 30 import org.chromium.content.browser.test.util.DOMUtils;
26 import org.chromium.content.browser.test.util.TestCallbackHelperContainer; 31 import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
27 import org.chromium.content.browser.test.util.TestInputMethodManagerWrapper; 32 import org.chromium.content.browser.test.util.TestInputMethodManagerWrapper;
28 import org.chromium.content.browser.test.util.TestInputMethodManagerWrapper.Rang e;
29 import org.chromium.content_public.browser.WebContents; 33 import org.chromium.content_public.browser.WebContents;
34 import org.chromium.content_public.browser.WebContentsObserver;
30 import org.chromium.content_shell_apk.ContentShellTestBase; 35 import org.chromium.content_shell_apk.ContentShellTestBase;
31 import org.chromium.ui.base.ime.TextInputType; 36 import org.chromium.ui.base.ime.TextInputType;
32 37
33 import java.util.ArrayList; 38 import java.util.ArrayList;
34 import java.util.Arrays; 39 import java.util.Arrays;
35 import java.util.List; 40 import java.util.List;
36 import java.util.concurrent.Callable; 41 import java.util.concurrent.Callable;
37 import java.util.concurrent.ExecutionException; 42 import java.util.concurrent.ExecutionException;
38 import java.util.concurrent.TimeoutException; 43 import java.util.concurrent.TimeoutException;
39 44
40 /** 45 /**
41 * Integration tests for text input using cases based on fixed regressions. 46 * Integration tests for text input using cases based on fixed regressions.
42 */ 47 */
43 public class ImeTest extends ContentShellTestBase { 48 public class ImeTest extends ContentShellTestBase {
44 private static final String DATA_URL = UrlUtils.encodeHtmlDataUri( 49 private static final String DATA_URL = UrlUtils.encodeHtmlDataUri(
45 "<html><head><meta name=\"viewport\"" 50 "<html><head><meta name=\"viewport\""
46 + "content=\"width=device-width\" /></head>" 51 + "content=\"width=device-width\" /></head>"
47 + "<body><form action=\"about:blank\">" 52 + "<body><form action=\"about:blank\">"
48 + "<input id=\"input_text\" type=\"text\" /><br/></form><form>" 53 + "<input id=\"input_text\" type=\"text\" /><br/></form><form>"
49 + "<br/><input id=\"input_radio\" type=\"radio\" style=\"width:50px; height:50px\" />" 54 + "<br/><input id=\"input_radio\" type=\"radio\" style=\"width:50px; height:50px\" />"
50 + "<br/><textarea id=\"textarea\" rows=\"4\" cols=\"20\"></textarea> " 55 + "<br/><textarea id=\"textarea\" rows=\"4\" cols=\"20\"></textarea> "
51 + "<br/><textarea id=\"textarea2\" rows=\"4\" cols=\"20\" autocomple te=\"off\">" 56 + "<br/><textarea id=\"textarea2\" rows=\"4\" cols=\"20\" autocomple te=\"off\">"
52 + "</textarea>" 57 + "</textarea>"
53 + "<br/><input id=\"input_number1\" type=\"number\" /><br/>" 58 + "<br/><input id=\"input_number1\" type=\"number\" /><br/>"
54 + "<br/><input id=\"input_number2\" type=\"number\" /><br/>" 59 + "<br/><input id=\"input_number2\" type=\"number\" /><br/>"
55 + "<br/><p><span id=\"plain_text\">This is Plain Text One</span></p> " 60 + "<br/><p><span id=\"plain_text\">This is Plain Text One</span></p> "
56 + "</form></body></html>"); 61 + "</form></body></html>");
57 62
58 private TestAdapterInputConnection mConnection; 63 private ChromiumBaseInputConnection mConnection;
59 private TestAdapterInputConnectionFactory mConnectionFactory; 64 private TestInputConnectionFactory mConnectionFactory;
60 private ImeAdapter mImeAdapter; 65 private ImeAdapter mImeAdapter;
61 66
62 private ContentViewCore mContentViewCore; 67 private ContentViewCore mContentViewCore;
63 private WebContents mWebContents; 68 private WebContents mWebContents;
64 private TestCallbackHelperContainer mCallbackContainer; 69 private TestCallbackHelperContainer mCallbackContainer;
65 private TestInputMethodManagerWrapper mInputMethodManagerWrapper; 70 private TestInputMethodManagerWrapper mInputMethodManagerWrapper;
66 71
67 @Override 72 @Override
68 public void setUp() throws Exception { 73 public void setUp() throws Exception {
69 super.setUp(); 74 super.setUp();
70 75
71 launchContentShellWithUrl(DATA_URL); 76 launchContentShellWithUrl(DATA_URL);
72 waitForActiveShellToBeDoneLoading(); 77 waitForActiveShellToBeDoneLoading();
73 mContentViewCore = getContentViewCore(); 78 mContentViewCore = getContentViewCore();
74 mWebContents = getWebContents(); 79 mWebContents = getWebContents();
75 80
76 mInputMethodManagerWrapper = new TestInputMethodManagerWrapper(mContentV iewCore); 81 mInputMethodManagerWrapper = new TestInputMethodManagerWrapper(mContentV iewCore);
77 getImeAdapter().setInputMethodManagerWrapperForTest(mInputMethodManagerW rapper); 82 getImeAdapter().setInputMethodManagerWrapperForTest(mInputMethodManagerW rapper);
78 assertEquals(0, mInputMethodManagerWrapper.getShowSoftInputCounter()); 83 assertEquals(0, mInputMethodManagerWrapper.getShowSoftInputCounter());
79 mConnectionFactory = new TestAdapterInputConnectionFactory(); 84 mConnectionFactory =
85 new TestInputConnectionFactory(getImeAdapter().getInputConnectio nFactoryForTest());
80 getImeAdapter().setInputConnectionFactory(mConnectionFactory); 86 getImeAdapter().setInputConnectionFactory(mConnectionFactory);
81 87
82 mCallbackContainer = new TestCallbackHelperContainer(mContentViewCore); 88 mCallbackContainer = new TestCallbackHelperContainer(mContentViewCore);
83 // TODO(aurimas) remove this wait once crbug.com/179511 is fixed. 89 // TODO(aurimas) remove this wait once crbug.com/179511 is fixed.
84 assertWaitForPageScaleFactorMatch(1); 90 assertWaitForPageScaleFactorMatch(1);
85 DOMUtils.waitForNonZeroNodeBounds(mWebContents, "input_text"); 91 DOMUtils.waitForNonZeroNodeBounds(mWebContents, "input_text");
86 DOMUtils.clickNode(this, mContentViewCore, "input_text"); 92 DOMUtils.clickNode(this, mContentViewCore, "input_text");
87 assertWaitForKeyboardStatus(true); 93 assertWaitForKeyboardStatus(true);
88 94
89 mConnection = (TestAdapterInputConnection) getAdapterInputConnection(); 95 mConnection = getInputConnection();
90 mImeAdapter = getImeAdapter(); 96 mImeAdapter = getImeAdapter();
91 97
92 waitAndVerifyStatesAndCalls(0, "", 0, 0, -1, -1); 98 if (usingReplicaInputConnection()) {
99 // This is not needed if onCreateInputConnection() can return correc t selection range.
100 waitAndVerifyUpdateSelection(0, 0, 0, -1, -1);
101 }
93 waitForKeyboardStates(1, 0, 1, new Integer[] {TextInputType.TEXT}); 102 waitForKeyboardStates(1, 0, 1, new Integer[] {TextInputType.TEXT});
94 assertEquals(0, mInputMethodManagerWrapper.getEditorInfo().initialSelSta rt); 103 assertEquals(0, mConnectionFactory.getOutAttrs().initialSelStart);
95 assertEquals(0, mInputMethodManagerWrapper.getEditorInfo().initialSelEnd ); 104 assertEquals(0, mConnectionFactory.getOutAttrs().initialSelEnd);
96 105
97 resetAllStates(); 106 resetAllStates();
98 } 107 }
99 108
100 private void assertNoFurtherStateUpdate(final int index) throws InterruptedE xception {
101 final List<TestImeState> states = mConnectionFactory.getImeStateList();
102 try {
103 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
104 @Override
105 public boolean isSatisfied() {
106 return states.size() > index;
107 }
108 });
109 fail("Unexpected updates pending");
110 } catch (AssertionError e) {
111 // TODO(tedchoc): This is horrible and should never timeout to deter mine success.
112 }
113 }
114
115 @MediumTest
116 @Feature({"TextInput", "Main"})
117 public void testSetUpGeneratesNoFurtherStateUpdate() throws Throwable {
118 assertNoFurtherStateUpdate(0);
119 waitForKeyboardStates(0, 0, 0, new Integer[] {});
120 }
121
122 @MediumTest 109 @MediumTest
123 @Feature({"TextInput", "Main"}) 110 @Feature({"TextInput", "Main"})
124 public void testKeyboardDismissedAfterClickingGo() throws Throwable { 111 public void testKeyboardDismissedAfterClickingGo() throws Throwable {
125 setComposingText("hello", 1); 112 setComposingText("hello", 1);
126 waitAndVerifyStatesAndCalls(0, "hello", 5, 5, 0, 5); 113 waitAndVerifyUpdateSelection(0, 5, 5, 0, 5);
127 114
128 performGo(mCallbackContainer); 115 performGo(mCallbackContainer);
129 116
130 assertWaitForKeyboardStatus(false); 117 assertWaitForKeyboardStatus(false);
131 } 118 }
119
120 @MediumTest
121 @Feature({"TextInput", "Main"})
122 public void testDoesNotHang_getTextAfterKeyboardHides() throws Throwable {
123 setComposingText("hello", 1);
124 waitAndVerifyUpdateSelection(0, 5, 5, 0, 5);
125
126 performGo(mCallbackContainer);
127
128 // This may time out if we do not get the information on time.
129 for (int i = 0; i < 100; ++i) {
130 getTextBeforeCursor(10, 0);
131 }
132
133 assertWaitForKeyboardStatus(false);
134 }
135
136 @MediumTest
137 @Feature({"TextInput", "Main"})
138 public void testDoesNotHang_rendererCrashes() throws Throwable {
no sievers 2016/02/25 01:41:44 per chat: can you remove this one and the test abo
Changwan Ryu 2016/02/25 01:56:12 Removed this test as it does not test anything. I
139 setComposingText("hello", 1);
140 waitAndVerifyUpdateSelection(0, 5, 5, 0, 5);
141
142 ThreadUtils.runOnUiThread(new Runnable() {
143 @Override
144 public void run() {
145 ObserverList.RewindableIterator<WebContentsObserver> observers =
146 getWebContents().getObserversForTesting();
147 while (observers.hasNext()) {
148 observers.next().renderProcessGone(false);
149 }
150 }
151 });
152
153 // This may time out if we do not get the information on time.
154 for (int i = 0; i < 100; ++i) {
155 getTextBeforeCursor(10, 0);
156 }
157
158 assertWaitForKeyboardStatus(false);
159 }
132 160
133 @SmallTest 161 @SmallTest
134 @Feature({"TextInput", "Main"}) 162 @Feature({"TextInput", "Main"})
135 public void testCommitWhileComposingText() throws Throwable { 163 public void testCommitWhileComposingText() throws Throwable {
136 setComposingText("h", 1); 164 setComposingText("h", 1);
137 waitAndVerifyStates(0, "h", 1, 1, 0, 1); 165 waitAndVerifyUpdateSelection(0, 1, 1, 0, 1);
138 166
139 setComposingText("he", 1); 167 setComposingText("he", 1);
140 waitAndVerifyStates(1, "he", 2, 2, 0, 2); 168 waitAndVerifyUpdateSelection(1, 2, 2, 0, 2);
141 169
142 setComposingText("hel", 1); 170 setComposingText("hel", 1);
143 waitAndVerifyStates(2, "hel", 3, 3, 0, 3); 171 waitAndVerifyUpdateSelection(2, 3, 3, 0, 3);
144 172
145 commitText("hel", 1); 173 commitText("hel", 1);
146 waitAndVerifyStates(3, "hel", 3, 3, -1, -1); 174 waitAndVerifyUpdateSelection(3, 3, 3, -1, -1);
175
176 setComposingText("lo", 1);
177 waitAndVerifyUpdateSelection(4, 5, 5, 3, 5);
178
179 commitText("", 1);
180 waitAndVerifyUpdateSelection(5, 3, 3, -1, -1);
181
182 assertTextsAroundCursor("hel", "", "");
147 } 183 }
148 184
149 @SmallTest 185 @SmallTest
150 @Feature({"TextInput", "Main"}) 186 @Feature({"TextInput", "Main"})
151 public void testCommitEnterKeyWhileComposingText() throws Throwable { 187 public void testCommitEnterKeyWhileComposingText() throws Throwable {
152 focusElementAndWaitForStateUpdate("textarea"); 188 focusElementAndWaitForStateUpdate("textarea");
153 189
154 setComposingText("hello", 1); 190 setComposingText("hello", 1);
155 waitAndVerifyStatesAndCalls(0, "hello", 5, 5, 0, 5); 191 waitAndVerifyUpdateSelection(0, 5, 5, 0, 5);
156 192
157 // Cancel the current composition and replace it with enter. 193 // Cancel the current composition and replace it with enter.
158 commitText("\n", 1); 194 commitText("\n", 1);
195 waitAndVerifyUpdateSelection(1, 1, 1, -1, -1);
159 // The second new line is not a user visible/editable one, it is a side- effect of Blink 196 // The second new line is not a user visible/editable one, it is a side- effect of Blink
160 // using <br> internally. This only happens when \n is at the end. 197 // using <br> internally. This only happens when \n is at the end.
161 waitAndVerifyStatesAndCalls(1, "\n\n", 1, 1, -1, -1); 198 assertTextsAroundCursor("\n", "", "\n");
162 199
163 commitText("world", 1); 200 commitText("world", 1);
164 waitAndVerifyStatesAndCalls(2, "\nworld", 6, 6, -1, -1); 201 waitAndVerifyUpdateSelection(2, 6, 6, -1, -1);
202 assertTextsAroundCursor("\nworld", "", "");
165 } 203 }
166 204
167 @SmallTest 205 @SmallTest
168 @Feature({"TextInput"}) 206 @Feature({"TextInput"})
169 public void testImeCopy() throws Exception { 207 public void testImeCopy() throws Exception {
170 commitText("hello", 1); 208 commitText("hello", 1);
171 waitAndVerifyStates(0, "hello", 5, 5, -1, -1); 209 waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
172 210
173 setSelection(2, 5); 211 setSelection(2, 5);
174 waitAndVerifyStates(1, "hello", 2, 5, -1, -1); 212 waitAndVerifyUpdateSelection(1, 2, 5, -1, -1);
175 213
176 copy(); 214 copy();
177 assertClipboardContents(getActivity(), "llo"); 215 assertClipboardContents(getActivity(), "llo");
178 } 216 }
179 217
180 @SmallTest 218 @SmallTest
181 @Feature({"TextInput"}) 219 @Feature({"TextInput"})
182 public void testEnterTextAndRefocus() throws Exception { 220 public void testEnterTextAndRefocus() throws Exception {
183 commitText("hello", 1); 221 commitText("hello", 1);
184 waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1); 222 waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
185 223 restartInput();
186 DOMUtils.clickNode(this, mContentViewCore, "input_radio");
187 assertWaitForKeyboardStatus(false);
188
189 DOMUtils.clickNode(this, mContentViewCore, "input_text"); 224 DOMUtils.clickNode(this, mContentViewCore, "input_text");
190 assertWaitForKeyboardStatus(true); 225 assertWaitForKeyboardStatus(true);
191 226
192 assertEquals(5, mInputMethodManagerWrapper.getEditorInfo().initialSelSta rt); 227 assertEquals(5, mConnectionFactory.getOutAttrs().initialSelStart);
193 assertEquals(5, mInputMethodManagerWrapper.getEditorInfo().initialSelEnd ); 228 assertEquals(5, mConnectionFactory.getOutAttrs().initialSelEnd);
194 } 229 }
195 230
196 @SmallTest 231 @SmallTest
197 @Feature({"TextInput"}) 232 @Feature({"TextInput"})
198 public void testShowAndHideSoftInput() throws Exception { 233 public void testShowAndHideSoftInput() throws Exception {
199 focusElement("input_radio", false); 234 focusElement("input_radio", false);
200 235
201 // hideSoftKeyboard(), restartInput() 236 // hideSoftKeyboard(), restartInput()
202 waitForKeyboardStates(0, 1, 1, new Integer[] {}); 237 waitForKeyboardStates(0, 1, 1, new Integer[] {});
203 238
204 // When input connection is null, we still need to set flags to prevent InputMethodService 239 // When input connection is null, we still need to set flags to prevent InputMethodService
205 // from entering fullscreen mode and from opening custom UI. 240 // from entering fullscreen mode and from opening custom UI.
206 assertNull(mInputMethodManagerWrapper.getInputConnection()); 241 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
207 assertEquals(EditorInfo.IME_FLAG_NO_FULLSCREEN | EditorInfo.IME_FLAG_NO_ EXTRACT_UI, 242 @Override
208 mInputMethodManagerWrapper.getEditorInfo().imeOptions); 243 public boolean isSatisfied() {
244 return getInputConnection() == null;
245 }
246 });
247 assertTrue(
248 (mConnectionFactory.getOutAttrs().imeOptions
249 & (EditorInfo.IME_FLAG_NO_FULLSCREEN | EditorInfo.IME_FL AG_NO_EXTRACT_UI))
250 != 0);
209 251
210 // showSoftInput(), restartInput() 252 // showSoftInput(), restartInput()
211 focusElement("input_number1"); 253 focusElement("input_number1");
212 waitForKeyboardStates(1, 1, 2, new Integer[] {TextInputType.NUMBER}); 254 waitForKeyboardStates(1, 1, 2, new Integer[] {TextInputType.NUMBER});
213 assertNotNull(mInputMethodManagerWrapper.getInputConnection()); 255 assertNotNull(mInputMethodManagerWrapper.getInputConnection());
214 256
215 focusElement("input_number2"); 257 focusElement("input_number2");
216 // Hide should never be called here. Otherwise we will see a flicker. Re started to 258 // Hide should never be called here. Otherwise we will see a flicker. Re started to
217 // reset internal states to handle the new input form. 259 // reset internal states to handle the new input form.
218 waitForKeyboardStates(2, 1, 3, new Integer[] {TextInputType.NUMBER, Text InputType.NUMBER}); 260 waitForKeyboardStates(2, 1, 3, new Integer[] {TextInputType.NUMBER, Text InputType.NUMBER});
219 261
220 focusElement("input_text"); 262 focusElement("input_text");
221 // showSoftInput() on input_text. restartInput() on input_number1 due to focus change, 263 // showSoftInput() on input_text. restartInput() on input_number1 due to focus change,
222 // and restartInput() on input_text later. 264 // and restartInput() on input_text later.
223 // TODO(changwan): reduce unnecessary restart input. 265 // TODO(changwan): reduce unnecessary restart input.
224 waitForKeyboardStates(3, 1, 5, new Integer[] { 266 waitForKeyboardStates(3, 1, 5, new Integer[] {
225 TextInputType.NUMBER, TextInputType.NUMBER, TextInputType.NUMBER , 267 TextInputType.NUMBER, TextInputType.NUMBER, TextInputType.NUMBER ,
226 TextInputType.TEXT}); 268 TextInputType.TEXT});
227 269
228 focusElement("input_radio", false); 270 focusElement("input_radio", false);
229 // hideSoftInput(), restartInput() 271 // hideSoftInput(), restartInput()
230 waitForKeyboardStates(3, 2, 6, new Integer[] { 272 waitForKeyboardStates(3, 2, 6, new Integer[] {
231 TextInputType.NUMBER, TextInputType.NUMBER, TextInputType.NUMBER , 273 TextInputType.NUMBER, TextInputType.NUMBER, TextInputType.NUMBER ,
232 TextInputType.TEXT}); 274 TextInputType.TEXT});
233 } 275 }
234 276
277 private void assertTextsAroundCursor(
278 CharSequence before, CharSequence selected, CharSequence after) thro ws Exception {
279 assertEquals(before, getTextBeforeCursor(100, 0));
280
281 CharSequence actualSelected = getSelectedText(0);
282 if (usingReplicaInputConnection() && TextUtils.isEmpty(actualSelected)) {
283 // ReplicaInputConnection will return null but ChromiumInputConnecti on will return "".
284 actualSelected = "";
285 }
286 assertEquals(selected, actualSelected);
287
288 if (usingReplicaInputConnection() && after.equals("\n")) {
289 // When the text ends with \n, we have a second new line that is not user
290 // visible/editable one, it is a side effect of using <br> internall y.
291 // Replica model simply deviates from the blink editor in this case.
292 assertEquals("", getTextAfterCursor(100, 0));
293 } else {
294 assertEquals(after, getTextAfterCursor(100, 0));
295 }
296 }
297
235 private void waitForKeyboardStates(int show, int hide, int restart, Integer[ ] history) 298 private void waitForKeyboardStates(int show, int hide, int restart, Integer[ ] history)
236 throws InterruptedException { 299 throws InterruptedException {
237 final String expected = stringifyKeyboardStates(show, hide, restart, his tory); 300 final String expected = stringifyKeyboardStates(show, hide, restart, his tory);
238 CriteriaHelper.pollForUIThreadCriteria(new Criteria() { 301 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
239 @Override 302 @Override
240 public boolean isSatisfied() { 303 public boolean isSatisfied() {
241 updateFailureReason( 304 updateFailureReason(
242 "Expected: {" + expected + "}, Actual: {" + getKeyboardS tates() + "}"); 305 "Expected: {" + expected + "}, Actual: {" + getKeyboardS tates() + "}");
243 return expected.equals(getKeyboardStates()); 306 return expected.equals(getKeyboardStates());
244 } 307 }
245 }); 308 });
246 } 309 }
247 310
248 private void resetAllStates() { 311 private void resetAllStates() {
249 mInputMethodManagerWrapper.resetCounters(); 312 mInputMethodManagerWrapper.reset();
250 mConnectionFactory.clearTextInputTypeHistory(); 313 mConnectionFactory.clearTextInputTypeHistory();
251 resetUpdateStateList();
252 } 314 }
253 315
254 private String getKeyboardStates() { 316 private String getKeyboardStates() {
255 try { 317 int showCount = mInputMethodManagerWrapper.getShowSoftInputCounter();
256 return ThreadUtils.runOnUiThreadBlocking(new Callable<String>() { 318 int hideCount = mInputMethodManagerWrapper.getHideSoftInputCounter();
257 @Override 319 int restartCount = mInputMethodManagerWrapper.getRestartInputCounter();
258 public String call() throws Exception { 320 Integer[] history = mConnectionFactory.getTextInputTypeHistory();
259 int showCount = mInputMethodManagerWrapper.getShowSoftInputC ounter(); 321 return stringifyKeyboardStates(showCount, hideCount, restartCount, histo ry);
260 int hideCount = mInputMethodManagerWrapper.getHideSoftInputC ounter();
261 int restartCount = mInputMethodManagerWrapper.getRestartInpu tCounter();
262 Integer[] history = mConnectionFactory.getTextInputTypeHisto ry();
263 return stringifyKeyboardStates(showCount, hideCount, restart Count, history);
264 }
265 });
266 } catch (ExecutionException e) {
267 e.printStackTrace();
268 return null;
269 }
270 } 322 }
271 323
272 private String stringifyKeyboardStates(int show, int hide, int restart, Inte ger[] history) { 324 private String stringifyKeyboardStates(int show, int hide, int restart, Inte ger[] history) {
273 return "show count: " + show + ", hide count: " + hide + ", restart coun t: " + restart 325 return "show count: " + show + ", hide count: " + hide + ", restart coun t: " + restart
274 + ", input type history: " + Arrays.deepToString(history); 326 + ", input type history: " + Arrays.deepToString(history);
275 } 327 }
276 328
277 @SmallTest 329 @SmallTest
278 @Feature({"TextInput"}) 330 @Feature({"TextInput"})
279 public void testKeyboardNotDismissedAfterCopySelection() throws Exception { 331 public void testKeyboardNotDismissedAfterCopySelection() throws Exception {
280 commitText("Sample Text", 1); 332 commitText("Sample Text", 1);
281 waitAndVerifyStatesAndCalls(0, "Sample Text", 11, 11, -1, -1); 333 waitAndVerifyUpdateSelection(0, 11, 11, -1, -1);
282 334
283 // This will select 'Text' part. 335 // This will select 'Text' part.
284 DOMUtils.clickNode(this, mContentViewCore, "input_text"); 336 DOMUtils.clickNode(this, mContentViewCore, "input_text");
285 assertWaitForKeyboardStatus(true); 337 assertWaitForKeyboardStatus(true);
286 338
287 // Wait until selection popup shows before long press. Otherwise view 339 // Wait until selection popup shows before long press. Otherwise view
288 // position may change during sleep in longPressNode implementation. 340 // position may change during sleep in longPressNode implementation.
289 assertWaitForSelectActionBarStatus(true); 341 assertWaitForSelectActionBarStatus(true);
290 342
291 DOMUtils.longPressNode(this, mContentViewCore, "input_text"); 343 DOMUtils.longPressNode(this, mContentViewCore, "input_text");
292 selectAll(); 344 selectAll();
293 copy(); 345 copy();
294 assertWaitForKeyboardStatus(true); 346 assertWaitForKeyboardStatus(true);
295 assertEquals(11, mInputMethodManagerWrapper.getSelection().end()); 347 assertEquals(11, mInputMethodManagerWrapper.getSelection().end());
296 } 348 }
297 349
298 @SmallTest 350 @SmallTest
299 @Feature({"TextInput"}) 351 @Feature({"TextInput"})
300 public void testImeNotDismissedAfterCutSelection() throws Exception { 352 public void testImeNotDismissedAfterCutSelection() throws Exception {
301 commitText("Sample Text", 1); 353 commitText("Sample Text", 1);
302 waitAndVerifyStatesAndCalls(0, "Sample Text", 11, 11, -1, -1); 354 waitAndVerifyUpdateSelection(0, 11, 11, -1, -1);
303 DOMUtils.longPressNode(this, mContentViewCore, "input_text"); 355 DOMUtils.longPressNode(this, mContentViewCore, "input_text");
304 assertWaitForSelectActionBarStatus(true); 356 assertWaitForSelectActionBarStatus(true);
305 assertWaitForKeyboardStatus(true); 357 assertWaitForKeyboardStatus(true);
306 cut(); 358 cut();
307 assertWaitForKeyboardStatus(true); 359 assertWaitForKeyboardStatus(true);
308 assertWaitForSelectActionBarStatus(false); 360 assertWaitForSelectActionBarStatus(false);
309 } 361 }
310 362
311 @SmallTest 363 @SmallTest
312 @Feature({"TextInput"}) 364 @Feature({"TextInput"})
(...skipping 14 matching lines...) Expand all
327 commitText("Sample Text", 1); 379 commitText("Sample Text", 1);
328 DOMUtils.longPressNode(this, mContentViewCore, "input_text"); 380 DOMUtils.longPressNode(this, mContentViewCore, "input_text");
329 assertWaitForSelectActionBarStatus(true); 381 assertWaitForSelectActionBarStatus(true);
330 } 382 }
331 383
332 @SmallTest 384 @SmallTest
333 @Feature({"TextInput"}) 385 @Feature({"TextInput"})
334 public void testLongPressInputWhileComposingText() throws Exception { 386 public void testLongPressInputWhileComposingText() throws Exception {
335 assertWaitForSelectActionBarStatus(false); 387 assertWaitForSelectActionBarStatus(false);
336 setComposingText("Sample Text", 1); 388 setComposingText("Sample Text", 1);
337 waitAndVerifyStatesAndCalls(0, "Sample Text", 11, 11, 0, 11); 389 waitAndVerifyUpdateSelection(0, 11, 11, 0, 11);
338 DOMUtils.longPressNode(this, mContentViewCore, "input_text"); 390 DOMUtils.longPressNode(this, mContentViewCore, "input_text");
339 391
340 assertWaitForSelectActionBarStatus(true); 392 assertWaitForSelectActionBarStatus(true);
341 393
342 // Long press will first change selection region, and then trigger IME a pp to show up. 394 // Long press will first change selection region, and then trigger IME a pp to show up.
343 // See RenderFrameImpl::didChangeSelection() and RenderWidget::didHandle GestureEvent(). 395 // See RenderFrameImpl::didChangeSelection() and RenderWidget::didHandle GestureEvent().
344 waitAndVerifyStatesAndCalls(1, "Sample Text", 7, 11, 0, 11); 396 waitAndVerifyUpdateSelection(1, 7, 11, 0, 11);
345 397
346 // Now IME app wants to finish composing text because an external select ion 398 // Now IME app wants to finish composing text because an external select ion
347 // change has been detected. At least Google Latin IME and Samsung IME 399 // change has been detected. At least Google Latin IME and Samsung IME
348 // behave this way. 400 // behave this way.
349 finishComposingText(); 401 finishComposingText();
350 waitAndVerifyStatesAndCalls(2, "Sample Text", 7, 11, -1, -1); 402 waitAndVerifyUpdateSelection(2, 7, 11, -1, -1);
351 } 403 }
352 404
353 @SmallTest 405 @SmallTest
354 @Feature({"TextInput"}) 406 @Feature({"TextInput"})
355 public void testImeShownWhenLongPressOnAlreadySelectedText() throws Exceptio n { 407 public void testImeShownWhenLongPressOnAlreadySelectedText() throws Exceptio n {
356 assertWaitForSelectActionBarStatus(false); 408 assertWaitForSelectActionBarStatus(false);
357 commitText("Sample Text", 1); 409 commitText("Sample Text", 1);
358 410
359 int showCount = mInputMethodManagerWrapper.getShowSoftInputCounter(); 411 int showCount = mInputMethodManagerWrapper.getShowSoftInputCounter();
360 DOMUtils.longPressNode(this, mContentViewCore, "input_text"); 412 DOMUtils.longPressNode(this, mContentViewCore, "input_text");
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
486 assertWaitForKeyboardStatus(true); 538 assertWaitForKeyboardStatus(true);
487 assertWaitForSelectActionBarStatus(true); 539 assertWaitForSelectActionBarStatus(true);
488 DOMUtils.longPressNode(this, mContentViewCore, "textarea"); 540 DOMUtils.longPressNode(this, mContentViewCore, "textarea");
489 assertWaitForKeyboardStatus(true); 541 assertWaitForKeyboardStatus(true);
490 } 542 }
491 543
492 @SmallTest 544 @SmallTest
493 @Feature({"TextInput"}) 545 @Feature({"TextInput"})
494 public void testImeCut() throws Exception { 546 public void testImeCut() throws Exception {
495 commitText("snarful", 1); 547 commitText("snarful", 1);
496 waitAndVerifyStatesAndCalls(0, "snarful", 7, 7, -1, -1); 548 waitAndVerifyUpdateSelection(0, 7, 7, -1, -1);
497 549
498 setSelection(1, 5); 550 setSelection(1, 5);
499 waitAndVerifyStatesAndCalls(1, "snarful", 1, 5, -1, -1); 551 waitAndVerifyUpdateSelection(1, 1, 5, -1, -1);
500 552
501 cut(); 553 cut();
502 waitAndVerifyStatesAndCalls(2, "sul", 1, 1, -1, -1); 554 waitAndVerifyUpdateSelection(2, 1, 1, -1, -1);
503 555 assertTextsAroundCursor("s", "", "ul");
504 assertClipboardContents(getActivity(), "narf"); 556 assertClipboardContents(getActivity(), "narf");
505 } 557 }
506 558
507 @SmallTest 559 @SmallTest
508 @Feature({"TextInput"}) 560 @Feature({"TextInput"})
509 public void testImePaste() throws Exception { 561 public void testImePaste() throws Exception {
510 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 562 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
511 @Override 563 @Override
512 public void run() { 564 public void run() {
513 ClipboardManager clipboardManager = 565 ClipboardManager clipboardManager =
514 (ClipboardManager) getActivity().getSystemService( 566 (ClipboardManager) getActivity().getSystemService(
515 Context.CLIPBOARD_SERVICE); 567 Context.CLIPBOARD_SERVICE);
516 clipboardManager.setPrimaryClip(ClipData.newPlainText("blarg", " blarg")); 568 clipboardManager.setPrimaryClip(ClipData.newPlainText("blarg", " blarg"));
517 } 569 }
518 }); 570 });
519 571
520 paste(); 572 paste();
521 waitAndVerifyStatesAndCalls(0, "blarg", 5, 5, -1, -1); 573 // Paste is a two step process when there is a non-zero selection.
574 waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
575 assertTextsAroundCursor("blarg", "", "");
522 576
523 setSelection(3, 5); 577 setSelection(3, 5);
524 waitAndVerifyStatesAndCalls(1, "blarg", 3, 5, -1, -1); 578 waitAndVerifyUpdateSelection(1, 3, 5, -1, -1);
579 assertTextsAroundCursor("bla", "rg", "");
525 580
526 paste(); 581 paste();
527 // Paste is a two step process when there is a non-zero selection. 582 // Paste is a two step process when there is a non-zero selection.
528 waitAndVerifyStates(2, "bla", 3, 3, -1, -1); 583 waitAndVerifyUpdateSelection(2, 3, 3, -1, -1);
529 waitAndVerifyStatesAndCalls(3, "blablarg", 8, 8, -1, -1); 584 waitAndVerifyUpdateSelection(3, 8, 8, -1, -1);
585 assertTextsAroundCursor("blablarg", "", "");
530 586
531 paste(); 587 paste();
532 waitAndVerifyStatesAndCalls(4, "blablargblarg", 13, 13, -1, -1); 588 waitAndVerifyUpdateSelection(4, 13, 13, -1, -1);
589 assertTextsAroundCursor("blablargblarg", "", "");
533 } 590 }
534 591
535 @SmallTest 592 @SmallTest
536 @Feature({"TextInput"}) 593 @Feature({"TextInput"})
537 public void testImeSelectAndUnSelectAll() throws Exception { 594 public void testImeSelectAndUnSelectAll() throws Exception {
538 commitText("hello", 1); 595 commitText("hello", 1);
539 waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1); 596 waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
540 597
541 selectAll(); 598 selectAll();
542 waitAndVerifyStatesAndCalls(1, "hello", 0, 5, -1, -1); 599 waitAndVerifyUpdateSelection(1, 0, 5, -1, -1);
543 600
544 unselect(); 601 unselect();
545 602
546 assertWaitForKeyboardStatus(false); 603 assertWaitForKeyboardStatus(false);
547 } 604 }
548 605
549 @SmallTest 606 @SmallTest
550 @Feature({"TextInput", "Main"}) 607 @Feature({"TextInput", "Main"})
551 public void testShowImeIfNeeded() throws Throwable { 608 public void testShowImeIfNeeded() throws Throwable {
552 // showImeIfNeeded() is now implicitly called by the updated focus 609 // showImeIfNeeded() is now implicitly called by the updated focus
553 // heuristic so no need to call explicitly. http://crbug.com/371927 610 // heuristic so no need to call explicitly. http://crbug.com/371927
554 DOMUtils.focusNode(mWebContents, "input_radio"); 611 DOMUtils.focusNode(mWebContents, "input_radio");
555 assertWaitForKeyboardStatus(false); 612 assertWaitForKeyboardStatus(false);
556 613
557 DOMUtils.focusNode(mWebContents, "input_text"); 614 DOMUtils.focusNode(mWebContents, "input_text");
558 assertWaitForKeyboardStatus(true); 615 assertWaitForKeyboardStatus(true);
559 } 616 }
560 617
561 @SmallTest 618 @SmallTest
562 @Feature({"TextInput", "Main"}) 619 @Feature({"TextInput", "Main"})
563 public void testFinishComposingText() throws Throwable { 620 public void testFinishComposingText() throws Throwable {
564 focusElementAndWaitForStateUpdate("textarea"); 621 focusElementAndWaitForStateUpdate("textarea");
565 622
566 commitText("hllo", 1); 623 commitText("hllo", 1);
567 waitAndVerifyStatesAndCalls(0, "hllo", 4, 4, -1, -1); 624 waitAndVerifyUpdateSelection(0, 4, 4, -1, -1);
568 625
569 commitText(" ", 1); 626 commitText(" ", 1);
570 waitAndVerifyStatesAndCalls(1, "hllo ", 5, 5, -1, -1); 627 waitAndVerifyUpdateSelection(1, 5, 5, -1, -1);
571 628
572 setSelection(1, 1); 629 setSelection(1, 1);
573 waitAndVerifyStatesAndCalls(2, "hllo ", 1, 1, -1, -1); 630 waitAndVerifyUpdateSelection(2, 1, 1, -1, -1);
631 assertTextsAroundCursor("h", "", "llo ");
574 632
575 setComposingRegion(0, 4); 633 setComposingRegion(0, 4);
576 waitAndVerifyStatesAndCalls(3, "hllo ", 1, 1, 0, 4); 634 waitAndVerifyUpdateSelection(3, 1, 1, 0, 4);
577 635
578 finishComposingText(); 636 finishComposingText();
579 waitAndVerifyStatesAndCalls(4, "hllo ", 1, 1, -1, -1); 637 waitAndVerifyUpdateSelection(4, 1, 1, -1, -1);
580 638
581 commitText("\n", 1); 639 commitText("\n", 1);
582 waitAndVerifyStatesAndCalls(5, "h\nllo ", 2, 2, -1, -1); 640 waitAndVerifyUpdateSelection(5, 2, 2, -1, -1);
641 assertTextsAroundCursor("h\n", "", "llo ");
583 } 642 }
584 643
585 /* 644 // http://crbug.com/445499
586 @SmallTest 645 @SmallTest
587 @Feature({"TextInput", "Main"}) 646 @Feature({"TextInput", "Main"})
588 http://crbug.com/445499
589 */
590 public void testDeleteText() throws Throwable { 647 public void testDeleteText() throws Throwable {
591 focusElement("textarea"); 648 focusElement("textarea");
592 649
593 // The calls below are a reflection of what the stock Google Keyboard (A ndr 650 // The calls below are a reflection of what the stock Google Keyboard (A ndr
594 // when the noted key is touched on screen. 651 // when the noted key is touched on screen.
595 // H 652 // H
596 resetUpdateStateList();
597 setComposingText("h", 1); 653 setComposingText("h", 1);
598 assertUpdateStateCall(1000); 654 assertEquals("h", getTextBeforeCursor(9, 0));
599 assertEquals("h", mConnection.getTextBeforeCursor(9, 0));
600 655
601 // O 656 // O
602 resetUpdateStateList();
603 setComposingText("ho", 1); 657 setComposingText("ho", 1);
604 assertUpdateStateCall(1000); 658 assertEquals("ho", getTextBeforeCursor(9, 0));
605 assertEquals("ho", mConnection.getTextBeforeCursor(9, 0));
606 659
607 resetUpdateStateList();
608 setComposingText("h", 1); 660 setComposingText("h", 1);
609 assertUpdateStateCall(1000);
610 setComposingRegion(0, 1); 661 setComposingRegion(0, 1);
611 setComposingText("h", 1); 662 setComposingText("h", 1);
612 assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); 663 assertEquals("h", getTextBeforeCursor(9, 0));
613 664
614 // I 665 // I
615 setComposingText("hi", 1); 666 setComposingText("hi", 1);
616 assertEquals("hi", mConnection.getTextBeforeCursor(9, 0)); 667 assertEquals("hi", getTextBeforeCursor(9, 0));
617 668
618 // SPACE 669 // SPACE
619 commitText("hi", 1); 670 commitText("hi", 1);
620 commitText(" ", 1); 671 commitText(" ", 1);
621 assertEquals("hi ", mConnection.getTextBeforeCursor(9, 0)); 672 assertEquals("hi ", getTextBeforeCursor(9, 0));
622 673
623 // DEL 674 // DEL
624 deleteSurroundingText(1, 0); 675 deleteSurroundingText(1, 0);
625 setComposingRegion(0, 2); 676 setComposingRegion(0, 2);
626 assertEquals("hi", mConnection.getTextBeforeCursor(9, 0)); 677 assertEquals("hi", getTextBeforeCursor(9, 0));
627 678
628 setComposingText("h", 1); 679 setComposingText("h", 1);
629 assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); 680 assertEquals("h", getTextBeforeCursor(9, 0));
630 681
631 commitText("", 1); 682 commitText("", 1);
632 assertEquals("", mConnection.getTextBeforeCursor(9, 0)); 683 assertEquals("", getTextBeforeCursor(9, 0));
633 684
634 // DEL (on empty input) 685 // DEL (on empty input)
635 deleteSurroundingText(1, 0); // DEL on empty still sends 1,0 686 deleteSurroundingText(1, 0); // DEL on empty still sends 1,0
636 assertEquals("", mConnection.getTextBeforeCursor(9, 0)); 687 assertEquals("", getTextBeforeCursor(9, 0));
637 } 688 }
638 689
639 690
640 /*
641 @SmallTest 691 @SmallTest
642 @Feature({"TextInput", "Main"}) 692 @Feature({"TextInput", "Main"})
643 */
644 public void testSwipingText() throws Throwable { 693 public void testSwipingText() throws Throwable {
645 focusElement("textarea"); 694 focusElement("textarea");
646 695
647 // The calls below are a reflection of what the stock Google Keyboard (A ndroid 4.4) sends 696 // The calls below are a reflection of what the stock Google Keyboard (A ndroid 4.4) sends
648 // when the word is swiped on the soft keyboard. Exercise care when alt ering to make sure 697 // when the word is swiped on the soft keyboard. Exercise care when alt ering to make sure
649 // that the test reflects reality. If this test breaks, it's possible t hat code has 698 // that the test reflects reality. If this test breaks, it's possible t hat code has
650 // changed and different calls need to be made instead. 699 // changed and different calls need to be made instead.
651 // "three" 700 // "three"
652 resetUpdateStateList();
653 setComposingText("three", 1); 701 setComposingText("three", 1);
654 assertUpdateStateCall(1000); 702 assertEquals("three", getTextBeforeCursor(99, 0));
655 assertEquals("three", mConnection.getTextBeforeCursor(99, 0));
656 703
657 // "word" 704 // "word"
658 commitText("three", 1); 705 commitText("three", 1);
659 commitText(" ", 1); 706 commitText(" ", 1);
660 setComposingText("word", 1); 707 setComposingText("word", 1);
661 resetUpdateStateList(); 708 assertEquals("three word", getTextBeforeCursor(99, 0));
662 assertUpdateStateCall(1000);
663 assertEquals("three word", mConnection.getTextBeforeCursor(99, 0));
664 709
665 // "test" 710 // "test"
666 commitText("word", 1); 711 commitText("word", 1);
667 commitText(" ", 1); 712 commitText(" ", 1);
668 resetUpdateStateList();
669 setComposingText("test", 1); 713 setComposingText("test", 1);
670 assertUpdateStateCall(1000); 714 assertEquals("three word test", getTextBeforeCursor(99, 0));
671 assertEquals("three word test", mConnection.getTextBeforeCursor(99, 0));
672 } 715 }
673 716
674 @SmallTest 717 @SmallTest
675 @Feature({"TextInput", "Main"}) 718 @Feature({"TextInput", "Main"})
676 public void testDeleteMultiCharacterCodepoint() throws Throwable { 719 public void testDeleteMultiCharacterCodepoint() throws Throwable {
677 // This smiley is a multi character codepoint. 720 // This smiley is a multi character codepoint.
678 final String smiley = "\uD83D\uDE0A"; 721 final String smiley = "\uD83D\uDE0A";
679 722
680 commitText(smiley, 1); 723 commitText(smiley, 1);
681 waitAndVerifyStatesAndCalls(0, smiley, 2, 2, -1, -1); 724 waitAndVerifyUpdateSelection(0, 2, 2, -1, -1);
725 assertTextsAroundCursor(smiley, "", "");
682 726
683 // DEL, sent via dispatchKeyEvent like it is in Android WebView or a phy sical keyboard. 727 // DEL, sent via dispatchKeyEvent like it is in Android WebView or a phy sical keyboard.
684 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL )); 728 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL ));
685 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)) ; 729 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)) ;
686 730
687 waitAndVerifyStatesAndCalls(1, "", 0, 0, -1, -1); 731 waitAndVerifyUpdateSelection(1, 0, 0, -1, -1);
688 732
689 // Make sure that we accept further typing after deleting the smiley. 733 // Make sure that we accept further typing after deleting the smiley.
690 setComposingText("s", 1); 734 setComposingText("s", 1);
691 waitAndVerifyStatesAndCalls(2, "s", 1, 1, 0, 1);
692 setComposingText("sm", 1); 735 setComposingText("sm", 1);
693 waitAndVerifyStatesAndCalls(3, "sm", 2, 2, 0, 2); 736 waitAndVerifyUpdateSelection(2, 1, 1, 0, 1);
737 waitAndVerifyUpdateSelection(3, 2, 2, 0, 2);
694 } 738 }
695 739
696 @SmallTest 740 @SmallTest
697 @Feature({"TextInput", "Main"}) 741 @Feature({"TextInput", "Main"})
698 public void testBackspaceKeycode() throws Throwable { 742 public void testBackspaceKeycode() throws Throwable {
699 focusElement("textarea"); 743 focusElement("textarea");
700 744
701 // H 745 // H
702 resetUpdateStateList();
703 commitText("h", 1); 746 commitText("h", 1);
704 assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); 747 assertEquals("h", getTextBeforeCursor(9, 0));
705 assertUpdateStateCall(1000);
706 assertEquals("h", mConnection.getTextBeforeCursor(9, 0));
707 748
708 // O 749 // O
709 resetUpdateStateList();
710 commitText("o", 1); 750 commitText("o", 1);
711 assertEquals("ho", mConnection.getTextBeforeCursor(9, 0)); 751 assertEquals("ho", getTextBeforeCursor(9, 0));
712 assertUpdateStateCall(1000);
713 assertEquals("ho", mConnection.getTextBeforeCursor(9, 0));
714 752
715 // DEL, sent via dispatchKeyEvent like it is in Android WebView or a phy sical keyboard. 753 // DEL, sent via dispatchKeyEvent like it is in Android WebView or a phy sical keyboard.
716 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL )); 754 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL ));
717 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)) ; 755 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)) ;
718 756
719 // DEL 757 // DEL
720 resetUpdateStateList(); 758 assertEquals("h", getTextBeforeCursor(9, 0));
721 assertEquals("h", mConnection.getTextBeforeCursor(9, 0));
722 assertUpdateStateCall(1000);
723 assertEquals("h", mConnection.getTextBeforeCursor(9, 0));
724 } 759 }
725 760
726 @SmallTest 761 @SmallTest
727 @Feature({"TextInput", "Main"}) 762 @Feature({"TextInput", "Main"})
728 public void testRepeatBackspaceKeycode() throws Throwable { 763 public void testRepeatBackspaceKeycode() throws Throwable {
729 focusElement("textarea"); 764 focusElement("textarea");
730 765
731 // H 766 // H
732 resetUpdateStateList();
733 commitText("h", 1); 767 commitText("h", 1);
734 assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); 768 assertEquals("h", getTextBeforeCursor(9, 0));
735 assertUpdateStateCall(1000);
736 assertEquals("h", mConnection.getTextBeforeCursor(9, 0));
737 769
738 // O 770 // O
739 resetUpdateStateList();
740 commitText("o", 1); 771 commitText("o", 1);
741 assertEquals("ho", mConnection.getTextBeforeCursor(9, 0)); 772 assertEquals("ho", getTextBeforeCursor(9, 0));
742 assertUpdateStateCall(1000);
743 assertEquals("ho", mConnection.getTextBeforeCursor(9, 0));
744 773
745 // Multiple keydowns should each delete one character (this is for physi cal keyboard 774 // Multiple keydowns should each delete one character (this is for physi cal keyboard
746 // key-repeat). 775 // key-repeat).
747 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL )); 776 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL ));
748 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL )); 777 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL ));
749 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)) ; 778 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)) ;
750 779
751 // DEL 780 // DEL
752 resetUpdateStateList(); 781 assertEquals("", getTextBeforeCursor(9, 0));
753 assertEquals("", mConnection.getTextBeforeCursor(9, 0));
754 assertUpdateStateCall(1000);
755 assertEquals("", mConnection.getTextBeforeCursor(9, 0));
756 } 782 }
757 783
758 @SmallTest 784 @SmallTest
759 @Feature({"TextInput", "Main"}) 785 @Feature({"TextInput", "Main"})
760 public void testPhysicalKeyboard() throws Throwable { 786 public void testPhysicalKeyboard() throws Throwable {
761 focusElementAndWaitForStateUpdate("textarea"); 787 focusElementAndWaitForStateUpdate("textarea");
762 788
763 // Type 'a' using a physical keyboard. 789 // Type 'a' using a physical keyboard.
764 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A)) ; 790 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A)) ;
765 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_A)); 791 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_A));
766 waitAndVerifyStatesAndCalls(0, "a", 1, 1, -1, -1); 792 waitAndVerifyUpdateSelection(0, 1, 1, -1, -1);
767 793
768 // Type 'enter' key. 794 // Type 'enter' key.
769 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENT ER)); 795 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENT ER));
770 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER )); 796 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER ));
771 waitAndVerifyStatesAndCalls(1, "a\n\n", 2, 2, -1, -1); 797 waitAndVerifyUpdateSelection(1, 2, 2, -1, -1);
798 assertTextsAroundCursor("a\n", "", "\n");
772 799
773 // Type 'b'. 800 // Type 'b'.
774 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)) ; 801 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)) ;
775 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_B)); 802 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_B));
776 waitAndVerifyStatesAndCalls(2, "a\nb", 3, 3, -1, -1); 803 waitAndVerifyUpdateSelection(2, 3, 3, -1, -1);
804 assertTextsAroundCursor("a\nb", "", "");
777 } 805 }
778 806
779 @SmallTest 807 @SmallTest
780 @Feature({"TextInput", "Main"}) 808 @Feature({"TextInput", "Main"})
781 public void testPhysicalKeyboard_AccentKeyCodes() throws Throwable { 809 public void testPhysicalKeyboard_AccentKeyCodes() throws Throwable {
782 focusElementAndWaitForStateUpdate("textarea"); 810 focusElementAndWaitForStateUpdate("textarea");
783 811
784 // h 812 // h
785 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_H)) ; 813 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_H)) ;
786 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_H)); 814 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_H));
787 assertEquals("h", mConnection.getTextBeforeCursor(9, 0)); 815 assertEquals("h", getTextBeforeCursor(9, 0));
788 waitAndVerifyStatesAndCalls(0, "h", 1, 1, -1, -1); 816 waitAndVerifyUpdateSelection(0, 1, 1, -1, -1);
789 817
790 // ALT-i (circumflex accent key on virtual keyboard) 818 // ALT-i (circumflex accent key on virtual keyboard)
791 dispatchKeyEvent(new KeyEvent( 819 dispatchKeyEvent(new KeyEvent(
792 0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META _ALT_ON)); 820 0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META _ALT_ON));
793 assertUpdateStateCall(1000); 821 assertEquals("hˆ", getTextBeforeCursor(9, 0));
794 assertEquals("hˆ", mConnection.getTextBeforeCursor(9, 0));
795 dispatchKeyEvent(new KeyEvent( 822 dispatchKeyEvent(new KeyEvent(
796 0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_A LT_ON)); 823 0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_A LT_ON));
797 assertEquals("hˆ", mConnection.getTextBeforeCursor(9, 0)); 824 assertEquals("hˆ", getTextBeforeCursor(9, 0));
798 waitAndVerifyStatesAndCalls(1, "hˆ", 2, 2, 1, 2); 825 waitAndVerifyUpdateSelection(1, 2, 2, 1, 2);
799 826
800 // o 827 // o
801 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_O)) ; 828 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_O)) ;
802 assertUpdateStateCall(1000); 829 assertEquals("hô", getTextBeforeCursor(9, 0));
803 assertEquals("hô", mConnection.getTextBeforeCursor(9, 0));
804 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_O)); 830 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_O));
805 assertEquals("hô", mConnection.getTextBeforeCursor(9, 0)); 831 assertEquals("hô", getTextBeforeCursor(9, 0));
806 waitAndVerifyStatesAndCalls(2, "hô", 2, 2, -1, -1); 832 waitAndVerifyUpdateSelection(2, 2, 2, -1, -1);
807 833
808 // ALT-i 834 // ALT-i
809 dispatchKeyEvent(new KeyEvent( 835 dispatchKeyEvent(new KeyEvent(
810 0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META _ALT_ON)); 836 0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META _ALT_ON));
811 assertUpdateStateCall(1000);
812 dispatchKeyEvent(new KeyEvent( 837 dispatchKeyEvent(new KeyEvent(
813 0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_A LT_ON)); 838 0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_A LT_ON));
814 assertEquals("hôˆ", mConnection.getTextBeforeCursor(9, 0)); 839 assertEquals("hôˆ", getTextBeforeCursor(9, 0));
815 waitAndVerifyStatesAndCalls(3, "hôˆ", 3, 3, 2, 3); 840 waitAndVerifyUpdateSelection(3, 3, 3, 2, 3);
816 841
817 // ALT-i again should have no effect 842 // ALT-i again should have no effect
818 dispatchKeyEvent(new KeyEvent( 843 dispatchKeyEvent(new KeyEvent(
819 0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META _ALT_ON)); 844 0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META _ALT_ON));
820 assertUpdateStateCall(1000);
821 dispatchKeyEvent(new KeyEvent( 845 dispatchKeyEvent(new KeyEvent(
822 0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_A LT_ON)); 846 0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_A LT_ON));
823 assertEquals("hôˆ", mConnection.getTextBeforeCursor(9, 0)); 847 assertEquals("hôˆ", getTextBeforeCursor(9, 0));
824 848
825 // b (cannot be accented, should just appear after) 849 // b (cannot be accented, should just appear after)
826 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)) ; 850 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)) ;
827 assertUpdateStateCall(1000); 851 assertEquals("hôˆb", getTextBeforeCursor(9, 0));
828 assertEquals("hôˆb", mConnection.getTextBeforeCursor(9, 0));
829 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_B)); 852 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_B));
830 assertEquals("hôˆb", mConnection.getTextBeforeCursor(9, 0)); 853 assertEquals("hôˆb", getTextBeforeCursor(9, 0));
831 // A transitional state due to finishComposingText. 854 int index = 4;
832 waitAndVerifyStates(4, "hôˆ", 3, 3, -1, -1); 855 if (usingReplicaInputConnection()) {
833 waitAndVerifyStatesAndCalls(5, "hôˆb", 4, 4, -1, -1); 856 // A transitional state due to finishComposingText.
857 waitAndVerifyUpdateSelection(index++, 3, 3, -1, -1);
858 }
859 waitAndVerifyUpdateSelection(index++, 4, 4, -1, -1);
834 860
835 // ALT-i 861 // ALT-i
836 dispatchKeyEvent(new KeyEvent( 862 dispatchKeyEvent(new KeyEvent(
837 0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META _ALT_ON)); 863 0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META _ALT_ON));
838 assertUpdateStateCall(1000);
839 dispatchKeyEvent(new KeyEvent( 864 dispatchKeyEvent(new KeyEvent(
840 0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_A LT_ON)); 865 0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_A LT_ON));
841 assertEquals("hôˆbˆ", mConnection.getTextBeforeCursor(9, 0)); 866 assertEquals("hôˆbˆ", getTextBeforeCursor(9, 0));
842 waitAndVerifyStatesAndCalls(6, "hôˆbˆ", 5, 5, 4, 5); 867 waitAndVerifyUpdateSelection(index++, 5, 5, 4, 5);
843 868
844 // Backspace 869 // Backspace
845 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL )); 870 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL ));
846 assertUpdateStateCall(1000); 871 assertEquals("hôˆb", getTextBeforeCursor(9, 0));
847 assertEquals("hôˆb", mConnection.getTextBeforeCursor(9, 0));
848 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)) ; 872 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)) ;
849 assertEquals("hôˆb", mConnection.getTextBeforeCursor(9, 0)); 873 assertEquals("hôˆb", getTextBeforeCursor(9, 0));
850 // A transitional state due to finishComposingText in deleteSurroundingT extImpl. 874 if (usingReplicaInputConnection()) {
851 waitAndVerifyStates(7, "hôˆbˆ", 5, 5, -1, -1); 875 // A transitional state due to finishComposingText in deleteSurround ingTextImpl.
852 waitAndVerifyStatesAndCalls(8, "hôˆb", 4, 4, -1, -1); 876 waitAndVerifyUpdateSelection(index++, 5, 5, -1, -1);
877 }
878 waitAndVerifyUpdateSelection(index++, 4, 4, -1, -1);
853 } 879 }
854 880
855 @SmallTest 881 @SmallTest
856 @Feature({"TextInput", "Main"}) 882 @Feature({"TextInput", "Main"})
857 public void testSetComposingRegionOutOfBounds() throws Throwable { 883 public void testSetComposingRegionOutOfBounds() throws Throwable {
858 focusElement("textarea"); 884 focusElement("textarea");
859 setComposingText("hello", 1); 885 setComposingText("hello", 1);
860 886
861 setComposingRegion(0, 0); 887 setComposingRegion(0, 0);
862 setComposingRegion(0, 9); 888 setComposingRegion(0, 9);
863 setComposingRegion(9, 0); 889 setComposingRegion(9, 0);
864 } 890 }
865 891
866 @SmallTest 892 @SmallTest
867 @Feature({"TextInput", "Main"}) 893 @Feature({"TextInput", "Main"})
868 public void testEnterKey_AfterCommitText() throws Throwable { 894 public void testEnterKey_AfterCommitText() throws Throwable {
869 focusElementAndWaitForStateUpdate("textarea"); 895 focusElementAndWaitForStateUpdate("textarea");
870 896
871 commitText("hello", 1); 897 commitText("hello", 1);
872 waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1); 898 waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
873 899
874 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENT ER)); 900 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENT ER));
875 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER )); 901 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER ));
876 // TODO(aurimas): remove this workaround when crbug.com/278584 is fixed. 902 waitAndVerifyUpdateSelection(1, 6, 6, -1, -1);
877 // The second new line is not a user visible/editable one, it is a side- effect of Blink 903 assertTextsAroundCursor("hello\n", "", "\n");
878 // using <br> internally. This only happens when \n is at the end.
879 waitAndVerifyStatesAndCalls(1, "hello\n\n", 6, 6, -1, -1);
880 904
881 commitText("world", 1); 905 commitText("world", 1);
882 waitAndVerifyStatesAndCalls(2, "hello\nworld", 11, 11, -1, -1); 906 waitAndVerifyUpdateSelection(2, 11, 11, -1, -1);
907 assertTextsAroundCursor("hello\nworld", "", "");
883 } 908 }
884 909
885 @SmallTest 910 @SmallTest
886 @Feature({"TextInput", "Main"}) 911 @Feature({"TextInput", "Main"})
887 public void testEnterKey_WhileComposingText() throws Throwable { 912 public void testEnterKey_WhileComposingText() throws Throwable {
888 focusElementAndWaitForStateUpdate("textarea"); 913 focusElementAndWaitForStateUpdate("textarea");
889 914
890 setComposingText("hello", 1); 915 setComposingText("hello", 1);
891 waitAndVerifyStatesAndCalls(0, "hello", 5, 5, 0, 5); 916 waitAndVerifyUpdateSelection(0, 5, 5, 0, 5);
917
918 // IME app should call this, otherwise enter key should clear the curren t composition.
919 finishComposingText();
920 waitAndVerifyUpdateSelection(1, 5, 5, -1, -1);
892 921
893 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENT ER)); 922 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENT ER));
894 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER )); 923 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER ));
895 924
896 // TODO(aurimas): remove this workaround when crbug.com/278584 is fixed.
897 // A transitional state due to finishComposingText.
898 waitAndVerifyStates(1, "hello", 5, 5, -1, -1);
899 // The second new line is not a user visible/editable one, it is a side- effect of Blink 925 // The second new line is not a user visible/editable one, it is a side- effect of Blink
900 // using <br> internally. This only happens when \n is at the end. 926 // using <br> internally. This only happens when \n is at the end.
901 waitAndVerifyStatesAndCalls(2, "hello\n\n", 6, 6, -1, -1); 927 waitAndVerifyUpdateSelection(2, 6, 6, -1, -1);
902 928
903 commitText("world", 1); 929 commitText("world", 1);
904 waitAndVerifyStatesAndCalls(3, "hello\nworld", 11, 11, -1, -1); 930 waitAndVerifyUpdateSelection(3, 11, 11, -1, -1);
931 assertTextsAroundCursor("hello\nworld", "", "");
905 } 932 }
906 933
907 @SmallTest 934 @SmallTest
908 @Feature({"TextInput", "Main"}) 935 @Feature({"TextInput", "Main"})
909 public void testDpadKeyCodesWhileSwipingText() throws Throwable { 936 public void testDpadKeyCodesWhileSwipingText() throws Throwable {
910 focusElement("textarea"); 937 focusElement("textarea");
911 938
912 // DPAD_CENTER should cause keyboard to appear 939 // DPAD_CENTER should cause keyboard to appear
913 resetUpdateStateList();
914 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPA D_CENTER)); 940 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPA D_CENTER));
915 assertUpdateStateCall(1000); 941
942 // TODO(changwan): should really check this.
916 } 943 }
917 944
918 @SmallTest 945 @SmallTest
919 @Feature({"TextInput", "Main"}) 946 @Feature({"TextInput", "Main"})
920 public void testNavigateTextWithDpadKeyCodes() throws Throwable { 947 public void testNavigateTextWithDpadKeyCodes() throws Throwable {
921 focusElementAndWaitForStateUpdate("textarea"); 948 focusElementAndWaitForStateUpdate("textarea");
922 949
923 commitText("hello", 1); 950 commitText("hello", 1);
924 waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1); 951 waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
925 952
926 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPA D_LEFT)); 953 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPA D_LEFT));
927 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_ LEFT)); 954 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_ LEFT));
928 955
929 // Ideally getTextBeforeCursor immediately after dispatchKeyEvent should return a correct 956 if (usingReplicaInputConnection()) {
930 // value, but we have a stop-gap solution in render_widget_input_handler and it make take 957 // Ideally getTextBeforeCursor immediately after dispatchKeyEvent sh ould return a
931 // some round trip time until we get the correct value. 958 // correct value, but we have a stop-gap solution in render_widget_i nput_handler and it
932 // TODO(changwan): Change the test not to wait when we fix it. 959 // make take some round trip time until we get the correct value.
933 waitUntilGetCharacterBeforeCursorBecomes("l"); 960 waitUntilGetCharacterBeforeCursorBecomes("l");
961 } else {
962 assertTextsAroundCursor("hell", "", "o");
963 }
934 } 964 }
935 965
936 private void waitUntilGetCharacterBeforeCursorBecomes(final String expectedT ext) 966 private void waitUntilGetCharacterBeforeCursorBecomes(final String expectedT ext)
937 throws InterruptedException { 967 throws InterruptedException {
938 CriteriaHelper.pollForUIThreadCriteria(new Criteria() { 968 pollForCriteriaOnThread(new Criteria() {
939 @Override 969 @Override
940 public boolean isSatisfied() { 970 public boolean isSatisfied() {
941 String actualText = (String) mConnection.getTextBeforeCursor(1, 0); 971 String actualText = (String) mConnection.getTextBeforeCursor(1, 0);
942 updateFailureReason("actualText: " + actualText); 972 updateFailureReason("actualText: " + actualText);
943 return expectedText.equals(actualText); 973 return expectedText.equals(actualText);
944 } 974 }
945 }); 975 });
946 } 976 }
947 977
978 private void pollForCriteriaOnThread(final Criteria criteria) throws Interru ptedException {
979 final Callable<Boolean> callable = new Callable<Boolean>() {
980 @Override
981 public Boolean call() throws Exception {
982 return criteria.isSatisfied();
983 }
984 };
985 CriteriaHelper.pollForCriteria(new Criteria() {
986 @Override
987 public boolean isSatisfied() {
988 try {
989 return runBlockingOnImeThread(callable);
990 } catch (Exception e) {
991 e.printStackTrace();
992 fail();
993 return false;
994 }
995 }
996
997 @Override
998 public String getFailureReason() {
999 return criteria.getFailureReason();
1000 }
1001 });
1002 }
1003
948 @SmallTest 1004 @SmallTest
949 @Feature({"TextInput"}) 1005 @Feature({"TextInput"})
950 public void testPastePopupShowAndHide() throws Throwable { 1006 public void testPastePopupShowAndHide() throws Throwable {
951 commitText("hello", 1); 1007 commitText("hello", 1);
952 waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1); 1008 waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
953 1009
954 selectAll(); 1010 selectAll();
955 waitAndVerifyStatesAndCalls(1, "hello", 0, 5, -1, -1); 1011 waitAndVerifyUpdateSelection(1, 0, 5, -1, -1);
1012 assertTextsAroundCursor("", "hello", "");
956 1013
957 cut(); 1014 cut();
958 waitAndVerifyStatesAndCalls(2, "", 0, 0, -1, -1); 1015 waitAndVerifyUpdateSelection(2, 0, 0, -1, -1);
1016 assertTextsAroundCursor("", "", "");
959 1017
960 DOMUtils.longPressNode(this, mContentViewCore, "input_text"); 1018 DOMUtils.longPressNode(this, mContentViewCore, "input_text");
961 CriteriaHelper.pollForUIThreadCriteria(new Criteria() { 1019 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
962 @Override 1020 @Override
963 public boolean isSatisfied() { 1021 public boolean isSatisfied() {
964 return mContentViewCore.isPastePopupShowing(); 1022 return mContentViewCore.isPastePopupShowing();
965 } 1023 }
966 }); 1024 });
967 1025
968 DOMUtils.clickNode(this, mContentViewCore, "input_text"); 1026 DOMUtils.clickNode(this, mContentViewCore, "input_text");
969 assertWaitForKeyboardStatus(true); 1027 assertWaitForKeyboardStatus(true);
970 DOMUtils.longPressNode(this, mContentViewCore, "input_text"); 1028 DOMUtils.longPressNode(this, mContentViewCore, "input_text");
971 setComposingText("h", 1); 1029 setComposingText("h", 1);
972 CriteriaHelper.pollForUIThreadCriteria(new Criteria() { 1030 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
973 @Override 1031 @Override
974 public boolean isSatisfied() { 1032 public boolean isSatisfied() {
975 return !mContentViewCore.isPastePopupShowing(); 1033 return !mContentViewCore.isPastePopupShowing();
976 } 1034 }
977 }); 1035 });
978 assertFalse(mContentViewCore.hasInsertion()); 1036 assertFalse(mContentViewCore.hasInsertion());
979 } 1037 }
980 1038
981 @SmallTest 1039 @SmallTest
982 @Feature({"TextInput"}) 1040 @Feature({"TextInput"})
983 public void testSelectionClearedOnKeyEvent() throws Throwable { 1041 public void testSelectionClearedOnKeyEvent() throws Throwable {
984 commitText("hello", 1); 1042 commitText("hello", 1);
985 waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1); 1043 waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
986 1044
987 DOMUtils.clickNode(this, mContentViewCore, "input_text"); 1045 DOMUtils.clickNode(this, mContentViewCore, "input_text");
988 assertWaitForKeyboardStatus(true); 1046 assertWaitForKeyboardStatus(true);
989 assertWaitForSelectActionBarStatus(true); 1047 assertWaitForSelectActionBarStatus(true);
990 1048
991 DOMUtils.longPressNode(this, mContentViewCore, "input_text"); 1049 DOMUtils.longPressNode(this, mContentViewCore, "input_text");
992 assertWaitForSelectActionBarStatus(true); 1050 assertWaitForSelectActionBarStatus(true);
993 1051
994 setComposingText("h", 1); 1052 setComposingText("h", 1);
995 assertWaitForSelectActionBarStatus(false); 1053 assertWaitForSelectActionBarStatus(false);
996 assertFalse(mContentViewCore.hasSelection()); 1054 assertFalse(mContentViewCore.hasSelection());
997 } 1055 }
998 1056
999 @SmallTest 1057 @SmallTest
1000 @Feature({"TextInput"}) 1058 @Feature({"TextInput"})
1001 public void testTextHandlesPreservedWithDpadNavigation() throws Throwable { 1059 public void testTextHandlesPreservedWithDpadNavigation() throws Throwable {
1002 DOMUtils.longPressNode(this, mContentViewCore, "plain_text"); 1060 DOMUtils.longPressNode(this, mContentViewCore, "plain_text");
1003 assertWaitForSelectActionBarStatus(true); 1061 assertWaitForSelectActionBarStatus(true);
1004 assertTrue(mContentViewCore.hasSelection()); 1062 assertTrue(mContentViewCore.hasSelection());
1005 1063
1006 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPA D_DOWN)); 1064 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPA D_DOWN));
1007 assertWaitForSelectActionBarStatus(true); 1065 assertWaitForSelectActionBarStatus(true);
1008 assertTrue(mContentViewCore.hasSelection()); 1066 assertTrue(mContentViewCore.hasSelection());
1009 } 1067 }
1010 1068
1011 @MediumTest 1069 @MediumTest
1012 @Feature({"TextInput"}) 1070 @Feature({"TextInput"})
1013 public void testRestartInputWhileComposingText() throws Throwable { 1071 public void testRestartInputWhileComposingText() throws Throwable {
1014 setComposingText("abc", 1); 1072 setComposingText("abc", 1);
1015 waitAndVerifyStatesAndCalls(0, "abc", 3, 3, 0, 3); 1073 waitAndVerifyUpdateSelection(0, 3, 3, 0, 3);
1016 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 1074 restartInput();
1017 @Override
1018 public void run() {
1019 mImeAdapter.restartInput();
1020 }
1021 });
1022 // We don't do anything when input gets restarted. But we depend on Andr oid's 1075 // We don't do anything when input gets restarted. But we depend on Andr oid's
1023 // InputMethodManager and/or input methods to call finishComposingText() in setting 1076 // InputMethodManager and/or input methods to call finishComposingText() in setting
1024 // current input connection as active or finishing the current input con nection. 1077 // current input connection as active or finishing the current input con nection.
1025 assertNoFurtherStateUpdate(1); 1078 Thread.sleep(1000);
1079 assertEquals(1, mInputMethodManagerWrapper.getUpdateSelectionList().size ());
1080 }
1081
1082 @MediumTest
1083 @Feature({"TextInput"})
1084 public void testRestartInputKeepsTextAndCursor() throws Exception {
1085 commitText("ab", 2);
1086 restartInput();
1087 assertEquals("ab", getTextBeforeCursor(10, 0));
1026 } 1088 }
1027 1089
1028 private void performGo(TestCallbackHelperContainer testCallbackHelperContain er) 1090 private void performGo(TestCallbackHelperContainer testCallbackHelperContain er)
1029 throws Throwable { 1091 throws Throwable {
1030 final AdapterInputConnection inputConnection = mConnection; 1092 final InputConnection inputConnection = mConnection;
1093 final Callable<Void> callable = new Callable<Void>() {
1094 @Override
1095 public Void call() throws Exception {
1096 inputConnection.performEditorAction(EditorInfo.IME_ACTION_GO);
1097 return null;
1098 }
1099 };
1100
1031 handleBlockingCallbackAction( 1101 handleBlockingCallbackAction(
1032 testCallbackHelperContainer.getOnPageFinishedHelper(), 1102 testCallbackHelperContainer.getOnPageFinishedHelper(),
1033 new Runnable() { 1103 new Runnable() {
1034 @Override 1104 @Override
1035 public void run() { 1105 public void run() {
1036 inputConnection.performEditorAction(EditorInfo.IME_ACTIO N_GO); 1106 try {
1107 runBlockingOnImeThread(callable);
1108 } catch (Exception e) {
1109 e.printStackTrace();
1110 fail();
1111 }
1037 } 1112 }
1038 }); 1113 });
1039 } 1114 }
1040 1115
1041 private void assertWaitForKeyboardStatus(final boolean show) throws Interrup tedException { 1116 private void assertWaitForKeyboardStatus(final boolean show) throws Interrup tedException {
1042 CriteriaHelper.pollForUIThreadCriteria(new Criteria() { 1117 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
1043 @Override 1118 @Override
1044 public boolean isSatisfied() { 1119 public boolean isSatisfied() {
1045 // We do not check the other way around: in some cases we need t o keep 1120 // We do not check the other way around: in some cases we need t o keep
1046 // input connection even when the last known status is 'hidden'. 1121 // input connection even when the last known status is 'hidden'.
1047 // See crbug.com/569332 for more details. 1122 if (show && getInputConnection() == null) {
1048 if (show && getAdapterInputConnection() == null) {
1049 updateFailureReason("input connection should not be null."); 1123 updateFailureReason("input connection should not be null.");
1050 return false; 1124 return false;
1051 } 1125 }
1052 updateFailureReason("expected show: " + show); 1126 updateFailureReason("expected show: " + show);
1053 return show == mInputMethodManagerWrapper.isShowWithoutHideOutst anding(); 1127 return show == mInputMethodManagerWrapper.isShowWithoutHideOutst anding();
1054 } 1128 }
1055 }); 1129 });
1056 } 1130 }
1057 1131
1058 private void assertWaitForSelectActionBarStatus( 1132 private void assertWaitForSelectActionBarStatus(
1059 final boolean show) throws InterruptedException { 1133 final boolean show) throws InterruptedException {
1060 CriteriaHelper.pollForUIThreadCriteria(new Criteria() { 1134 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
1061 @Override 1135 @Override
1062 public boolean isSatisfied() { 1136 public boolean isSatisfied() {
1063 return show == mContentViewCore.isSelectActionBarShowing(); 1137 return show == mContentViewCore.isSelectActionBarShowing();
1064 } 1138 }
1065 }); 1139 });
1066 } 1140 }
1067 1141
1068 private void waitAndVerifyStates(final int index, String text, final int sel ectionStart, 1142 private void waitAndVerifyUpdateSelection(final int index, final int selecti onStart,
1069 final int selectionEnd, final int compositionStart, final int compos itionEnd) 1143 final int selectionEnd, final int compositionStart, final int compos itionEnd)
1070 throws InterruptedException { 1144 throws InterruptedException {
1071 final List<TestImeState> states = mConnectionFactory.getImeStateList(); 1145 final List<Pair<Range, Range>> states = mInputMethodManagerWrapper.getUp dateSelectionList();
1072 CriteriaHelper.pollForUIThreadCriteria(new Criteria() { 1146 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
1073 @Override 1147 @Override
1074 public boolean isSatisfied() { 1148 public boolean isSatisfied() {
1075 return states.size() > index; 1149 return states.size() > index;
1076 } 1150 }
1077 }); 1151 });
1078 states.get(index).assertEqualState( 1152 Pair<Range, Range> selection = states.get(index);
1079 text, selectionStart, selectionEnd, compositionStart, compositio nEnd); 1153 assertEquals(selectionStart, selection.first.start());
1154 assertEquals(selectionEnd, selection.first.end());
1155 assertEquals(compositionStart, selection.second.start());
1156 assertEquals(compositionEnd, selection.second.end());
1080 } 1157 }
1081 1158
1082 private void waitAndVerifyStatesAndCalls(final int index, String text, final int selectionStart, 1159 private void resetUpdateSelectionList() {
1083 final int selectionEnd, final int compositionStart, final int compos itionEnd) 1160 mInputMethodManagerWrapper.getUpdateSelectionList().clear();
1084 throws InterruptedException {
1085 waitAndVerifyStates(
1086 index, text, selectionStart, selectionEnd, compositionStart, com positionEnd);
1087
1088 // Wait and verify calls to InputMethodManager.
1089 final Range selection = new Range(selectionStart, selectionEnd);
1090 final Range composition = new Range(compositionStart, compositionEnd);
1091 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
1092 @Override
1093 public boolean isSatisfied() {
1094 updateFailureReason(
1095 "Actual selection was: " + mInputMethodManagerWrapper.ge tSelection()
1096 + ", and actual composition was: "
1097 + mInputMethodManagerWrapper.getComposition());
1098 return mInputMethodManagerWrapper.getSelection().equals(selectio n)
1099 && mInputMethodManagerWrapper.getComposition().equals(co mposition);
1100 }
1101 });
1102 }
1103
1104 private void resetUpdateStateList() {
1105 mConnectionFactory.getImeStateList().clear();
1106 }
1107
1108 private void assertUpdateStateCall(int maxms) throws Exception {
1109 while (mConnectionFactory.getImeStateList().size() == 0 && maxms > 0) {
1110 try {
1111 Thread.sleep(50);
1112 } catch (Exception e) {
1113 // Not really a problem since we're just going to sleep again.
1114 }
1115 maxms -= 50;
1116 }
1117 assertTrue(mConnectionFactory.getImeStateList().size() > 0);
1118 } 1161 }
1119 1162
1120 private void assertClipboardContents(final Activity activity, final String e xpectedContents) 1163 private void assertClipboardContents(final Activity activity, final String e xpectedContents)
1121 throws InterruptedException { 1164 throws InterruptedException {
1122 CriteriaHelper.pollForUIThreadCriteria(new Criteria() { 1165 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
1123 @Override 1166 @Override
1124 public boolean isSatisfied() { 1167 public boolean isSatisfied() {
1125 ClipboardManager clipboardManager = 1168 ClipboardManager clipboardManager =
1126 (ClipboardManager) activity.getSystemService(Context.CLI PBOARD_SERVICE); 1169 (ClipboardManager) activity.getSystemService(Context.CLI PBOARD_SERVICE);
1127 ClipData clip = clipboardManager.getPrimaryClip(); 1170 ClipData clip = clipboardManager.getPrimaryClip();
1128 return clip != null && clip.getItemCount() == 1 1171 return clip != null && clip.getItemCount() == 1
1129 && TextUtils.equals(clip.getItemAt(0).getText(), expecte dContents); 1172 && TextUtils.equals(clip.getItemAt(0).getText(), expecte dContents);
1130 } 1173 }
1131 }); 1174 });
1132 } 1175 }
1133 1176
1134 private ImeAdapter getImeAdapter() { 1177 private ImeAdapter getImeAdapter() {
1135 return mContentViewCore.getImeAdapterForTest(); 1178 return mContentViewCore.getImeAdapterForTest();
1136 } 1179 }
1137 1180
1138 private AdapterInputConnection getAdapterInputConnection() { 1181 private ChromiumBaseInputConnection getInputConnection() {
1139 return mContentViewCore.getImeAdapterForTest().getInputConnectionForTest (); 1182 try {
1183 return ThreadUtils.runOnUiThreadBlocking(new Callable<ChromiumBaseIn putConnection>() {
1184 @Override
1185 public ChromiumBaseInputConnection call() {
1186 return mContentViewCore.getImeAdapterForTest().getInputConne ctionForTest();
1187 }
1188 });
1189 } catch (ExecutionException e) {
1190 e.printStackTrace();
1191 fail();
1192 return null;
1193 }
1194 }
1195
1196 private void restartInput() {
1197 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
1198 @Override
1199 public void run() {
1200 mImeAdapter.restartInput();
1201 }
1202 });
1140 } 1203 }
1141 1204
1142 private void copy() { 1205 private void copy() {
1143 final WebContents webContents = mWebContents; 1206 final WebContents webContents = mWebContents;
1144 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 1207 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
1145 @Override 1208 @Override
1146 public void run() { 1209 public void run() {
1147 webContents.copy(); 1210 webContents.copy();
1148 } 1211 }
1149 }); 1212 });
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1182 private void unselect() { 1245 private void unselect() {
1183 final WebContents webContents = mWebContents; 1246 final WebContents webContents = mWebContents;
1184 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 1247 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
1185 @Override 1248 @Override
1186 public void run() { 1249 public void run() {
1187 webContents.unselect(); 1250 webContents.unselect();
1188 } 1251 }
1189 }); 1252 });
1190 } 1253 }
1191 1254
1192 private void commitText(final CharSequence text, final int newCursorPosition ) { 1255 private <T> T runBlockingOnImeThread(Callable<T> c) throws Exception {
1193 final AdapterInputConnection connection = mConnection; 1256 return ImeTestUtils.runBlockingOnHandler(mConnectionFactory.getHandler() , c);
1194 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 1257 }
1258
1259 private boolean commitText(final CharSequence text, final int newCursorPosit ion)
1260 throws Exception {
1261 final ChromiumBaseInputConnection connection = mConnection;
1262 return runBlockingOnImeThread(new Callable<Boolean>() {
1195 @Override 1263 @Override
1196 public void run() { 1264 public Boolean call() {
1197 connection.commitText(text, newCursorPosition); 1265 return connection.commitText(text, newCursorPosition);
1198 } 1266 }
1199 }); 1267 });
1200 } 1268 }
1201 1269
1202 private void setSelection(final int start, final int end) { 1270 private boolean setSelection(final int start, final int end) throws Exceptio n {
1203 final AdapterInputConnection connection = mConnection; 1271 final ChromiumBaseInputConnection connection = mConnection;
1204 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 1272 return runBlockingOnImeThread(new Callable<Boolean>() {
1205 @Override 1273 @Override
1206 public void run() { 1274 public Boolean call() {
1207 connection.setSelection(start, end); 1275 return connection.setSelection(start, end);
1208 } 1276 }
1209 }); 1277 });
1210 } 1278 }
1211 1279
1212 private void setComposingRegion(final int start, final int end) { 1280 private boolean setComposingRegion(final int start, final int end) throws Ex ception {
1213 final AdapterInputConnection connection = mConnection; 1281 final ChromiumBaseInputConnection connection = mConnection;
1214 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 1282 return runBlockingOnImeThread(new Callable<Boolean>() {
1215 @Override 1283 @Override
1216 public void run() { 1284 public Boolean call() {
1217 connection.setComposingRegion(start, end); 1285 return connection.setComposingRegion(start, end);
1218 } 1286 }
1219 }); 1287 });
1220 } 1288 }
1221 1289
1222 private void setComposingText(final CharSequence text, final int newCursorPo sition) { 1290 private boolean setComposingText(final CharSequence text, final int newCurso rPosition)
1223 final AdapterInputConnection connection = mConnection; 1291 throws Exception {
1224 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 1292 final ChromiumBaseInputConnection connection = mConnection;
1293 return runBlockingOnImeThread(new Callable<Boolean>() {
1225 @Override 1294 @Override
1226 public void run() { 1295 public Boolean call() {
1227 connection.setComposingText(text, newCursorPosition); 1296 return connection.setComposingText(text, newCursorPosition);
1228 } 1297 }
1229 }); 1298 });
1230 } 1299 }
1231 1300
1232 private void finishComposingText() { 1301 private boolean finishComposingText() throws Exception {
1233 final AdapterInputConnection connection = mConnection; 1302 final ChromiumBaseInputConnection connection = mConnection;
1234 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 1303 return runBlockingOnImeThread(new Callable<Boolean>() {
1235 @Override 1304 @Override
1236 public void run() { 1305 public Boolean call() {
1237 connection.finishComposingText(); 1306 return connection.finishComposingText();
1238 } 1307 }
1239 }); 1308 });
1240 } 1309 }
1241 1310
1242 private void deleteSurroundingText(final int before, final int after) { 1311 private boolean deleteSurroundingText(final int before, final int after) thr ows Exception {
1243 final AdapterInputConnection connection = mConnection; 1312 final ChromiumBaseInputConnection connection = mConnection;
1244 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 1313 return runBlockingOnImeThread(new Callable<Boolean>() {
1245 @Override 1314 @Override
1246 public void run() { 1315 public Boolean call() {
1247 connection.deleteSurroundingText(before, after); 1316 return connection.deleteSurroundingText(before, after);
1248 } 1317 }
1249 }); 1318 });
1250 } 1319 }
1320
1321 private CharSequence getTextBeforeCursor(final int length, final int flags) throws Exception {
1322 final ChromiumBaseInputConnection connection = mConnection;
1323 return runBlockingOnImeThread(new Callable<CharSequence>() {
1324 @Override
1325 public CharSequence call() {
1326 return connection.getTextBeforeCursor(length, flags);
1327 }
1328 });
1329 }
1330
1331 private CharSequence getSelectedText(final int flags) throws Exception {
1332 final ChromiumBaseInputConnection connection = mConnection;
1333 return runBlockingOnImeThread(new Callable<CharSequence>() {
1334 @Override
1335 public CharSequence call() {
1336 return connection.getSelectedText(flags);
1337 }
1338 });
1339 }
1340
1341 private CharSequence getTextAfterCursor(final int length, final int flags) t hrows Exception {
1342 final ChromiumBaseInputConnection connection = mConnection;
1343 return runBlockingOnImeThread(new Callable<CharSequence>() {
1344 @Override
1345 public CharSequence call() {
1346 return connection.getTextAfterCursor(length, flags);
1347 }
1348 });
1349 }
1251 1350
1252 private void dispatchKeyEvent(final KeyEvent event) { 1351 private void dispatchKeyEvent(final KeyEvent event) {
1253 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 1352 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
1254 @Override 1353 @Override
1255 public void run() { 1354 public void run() {
1256 mImeAdapter.dispatchKeyEvent(event); 1355 mImeAdapter.dispatchKeyEvent(event);
1257 } 1356 }
1258 }); 1357 });
1259 } 1358 }
1260 1359
1261 /** 1360 /**
1262 * Focus element, wait for a single state update, reset state update list. 1361 * Focus element, wait for a single state update, reset state update list.
1263 * @param id ID of the element to focus. 1362 * @param id ID of the element to focus.
1264 */ 1363 */
1265 private void focusElementAndWaitForStateUpdate(String id) 1364 private void focusElementAndWaitForStateUpdate(String id)
1266 throws InterruptedException, TimeoutException { 1365 throws InterruptedException, TimeoutException {
1267 focusElement(id); 1366 focusElement(id);
1268 waitAndVerifyStatesAndCalls(0, "", 0, 0, -1, -1); 1367 waitAndVerifyUpdateSelection(0, 0, 0, -1, -1);
1269 resetUpdateStateList(); 1368 resetUpdateSelectionList();
1270 } 1369 }
1271 1370
1272 private void focusElement(final String id) throws InterruptedException, Time outException { 1371 private void focusElement(final String id) throws InterruptedException, Time outException {
1273 focusElement(id, true); 1372 focusElement(id, true);
1274 } 1373 }
1275 1374
1276 private void focusElement(final String id, boolean shouldShowKeyboard) 1375 private void focusElement(final String id, boolean shouldShowKeyboard)
1277 throws InterruptedException, TimeoutException { 1376 throws InterruptedException, TimeoutException {
1278 DOMUtils.focusNode(mWebContents, id); 1377 DOMUtils.focusNode(mWebContents, id);
1279 assertWaitForKeyboardStatus(shouldShowKeyboard); 1378 assertWaitForKeyboardStatus(shouldShowKeyboard);
1280 CriteriaHelper.pollForCriteria(new Criteria() { 1379 CriteriaHelper.pollForCriteria(new Criteria() {
1281 @Override 1380 @Override
1282 public boolean isSatisfied() { 1381 public boolean isSatisfied() {
1283 try { 1382 try {
1284 return id.equals(DOMUtils.getFocusedNode(mWebContents)); 1383 return id.equals(DOMUtils.getFocusedNode(mWebContents));
1285 } catch (Exception e) { 1384 } catch (Exception e) {
1286 return false; 1385 return false;
1287 } 1386 }
1288 } 1387 }
1289 }); 1388 });
1290 // When we focus another element, the connection may be recreated. 1389 // When we focus another element, the connection may be recreated.
1291 mConnection = (TestAdapterInputConnection) getAdapterInputConnection(); 1390 mConnection = getInputConnection();
1292 } 1391 }
1293 1392
1294 private static class TestAdapterInputConnectionFactory extends 1393 private boolean usingReplicaInputConnection() {
1295 ImeAdapter.AdapterInputConnectionFactory { 1394 return mConnectionFactory.getHandler().getLooper() == Looper.getMainLoop er();
1296 private final List<TestImeState> mImeStateList = new ArrayList<>(); 1395 }
1396
1397 private static class TestInputConnectionFactory implements ChromiumBaseInput Connection.Factory {
1398 private final ChromiumBaseInputConnection.Factory mFactory;
1399
1297 private final List<Integer> mTextInputTypeList = new ArrayList<>(); 1400 private final List<Integer> mTextInputTypeList = new ArrayList<>();
1401 private EditorInfo mOutAttrs;
1402
1403 public TestInputConnectionFactory(ChromiumBaseInputConnection.Factory fa ctory) {
1404 mFactory = factory;
1405 }
1298 1406
1299 @Override 1407 @Override
1300 public AdapterInputConnection get(View view, ImeAdapter imeAdapter, int initialSelStart, 1408 public ChromiumBaseInputConnection initializeAndGet(View view, ImeAdapte r imeAdapter,
1301 int initialSelEnd, EditorInfo outAttrs) { 1409 int inputType, int inputFlags, int selectionStart, int selection End,
1302 mTextInputTypeList.add(imeAdapter.getTextInputType()); 1410 EditorInfo outAttrs) {
1303 return new TestAdapterInputConnection( 1411 mTextInputTypeList.add(inputType);
1304 mImeStateList, view, imeAdapter, initialSelStart, initialSel End, outAttrs); 1412 mOutAttrs = outAttrs;
1413 return mFactory.initializeAndGet(view, imeAdapter, inputType, inputF lags,
1414 selectionStart, selectionEnd, outAttrs);
1305 } 1415 }
1306 1416
1307 public List<TestImeState> getImeStateList() { 1417 @Override
1308 return mImeStateList; 1418 public Handler getHandler() {
1419 return mFactory.getHandler();
1309 } 1420 }
1310 1421
1311 public Integer[] getTextInputTypeHistory() { 1422 public Integer[] getTextInputTypeHistory() {
1312 Integer[] result = new Integer[mTextInputTypeList.size()]; 1423 Integer[] result = new Integer[mTextInputTypeList.size()];
1313 mTextInputTypeList.toArray(result); 1424 mTextInputTypeList.toArray(result);
1314 return result; 1425 return result;
1315 } 1426 }
1316 1427
1317 public void clearTextInputTypeHistory() { 1428 public void clearTextInputTypeHistory() {
1318 mTextInputTypeList.clear(); 1429 mTextInputTypeList.clear();
1319 } 1430 }
1320 }
1321 1431
1322 private static class TestAdapterInputConnection extends AdapterInputConnecti on { 1432 public EditorInfo getOutAttrs() {
1323 private final List<TestImeState> mImeStateList; 1433 return mOutAttrs;
1324
1325 public TestAdapterInputConnection(List<TestImeState> imeStateList, View view,
1326 ImeAdapter imeAdapter, int initialSelStart, int initialSelEnd,
1327 EditorInfo outAttrs) {
1328 super(view, imeAdapter, initialSelStart, initialSelEnd, outAttrs);
1329 mImeStateList = imeStateList;
1330 }
1331
1332 @Override
1333 public void updateState(String text, int selectionStart, int selectionEn d,
1334 int compositionStart, int compositionEnd, boolean requiredAck) {
1335 mImeStateList.add(new TestImeState(
1336 text, selectionStart, selectionEnd, compositionStart, compos itionEnd));
1337 super.updateState(text, selectionStart, selectionEnd, compositionSta rt,
1338 compositionEnd, requiredAck);
1339 }
1340 }
1341
1342 private static class TestImeState {
1343 private final String mText;
1344 private final int mSelectionStart;
1345 private final int mSelectionEnd;
1346 private final int mCompositionStart;
1347 private final int mCompositionEnd;
1348
1349 public TestImeState(String text, int selectionStart, int selectionEnd,
1350 int compositionStart, int compositionEnd) {
1351 mText = text;
1352 mSelectionStart = selectionStart;
1353 mSelectionEnd = selectionEnd;
1354 mCompositionStart = compositionStart;
1355 mCompositionEnd = compositionEnd;
1356 }
1357
1358 public void assertEqualState(String text, int selectionStart, int select ionEnd,
1359 int compositionStart, int compositionEnd) {
1360 assertEquals("Text did not match", text, mText);
1361 assertEquals("Selection start did not match", selectionStart, mSelec tionStart);
1362 assertEquals("Selection end did not match", selectionEnd, mSelection End);
1363 assertEquals("Composition start did not match", compositionStart, mC ompositionStart);
1364 assertEquals("Composition end did not match", compositionEnd, mCompo sitionEnd);
1365 } 1434 }
1366 } 1435 }
1367 } 1436 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698