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

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

Powered by Google App Engine
This is Rietveld 408576698