ImeTest.java revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
19720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// Copyright 2013 The Chromium Authors. All rights reserved. 29720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// Use of this source code is governed by a BSD-style license that can be 39720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block// found in the LICENSE file. 49720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 59720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockpackage org.chromium.content.browser.input; 69720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 79720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport android.app.Activity; 89720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport android.content.ClipData; 99720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport android.content.ClipboardManager; 109720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport android.content.Context; 119720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport android.test.suitebuilder.annotation.MediumTest; 129720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport android.test.suitebuilder.annotation.SmallTest; 139720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport android.text.Editable; 149720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport android.text.TextUtils; 159720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport android.view.KeyEvent; 169720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport android.view.View; 179720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport android.view.inputmethod.EditorInfo; 189720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 199720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport org.chromium.base.ThreadUtils; 209720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport org.chromium.base.test.util.Feature; 219720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport org.chromium.base.test.util.UrlUtils; 229720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport org.chromium.content.browser.ContentView; 239720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport org.chromium.content.browser.ContentViewCore; 249720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport org.chromium.content.browser.test.util.Criteria; 259720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport org.chromium.content.browser.test.util.CriteriaHelper; 269720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport org.chromium.content.browser.test.util.DOMUtils; 279720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport org.chromium.content.browser.test.util.TestCallbackHelperContainer; 289720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport org.chromium.content.browser.test.util.TestInputMethodManagerWrapper; 299720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport org.chromium.content_shell_apk.ContentShellTestBase; 309720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 319720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport java.util.ArrayList; 329720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockimport java.util.concurrent.Callable; 339720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 349720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block/** 359720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block * Integration tests for text input using cases based on fixed regressions. 369720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block */ 379720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Blockpublic class ImeTest extends ContentShellTestBase { 389720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 399720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block private static final String DATA_URL = UrlUtils.encodeHtmlDataUri( 409720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block "<html><head><meta name=\"viewport\"" + 419720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block "content=\"width=device-width, initial-scale=2.0, maximum-scale=2.0\" /></head>" + 429720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block "<body><form action=\"about:blank\">" + 439720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block "<input id=\"input_text\" type=\"text\" /><br/>" + 449720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block "<input id=\"input_radio\" type=\"radio\" style=\"width:50px;height:50px\" />" + 459720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block "<br/><textarea id=\"textarea\" rows=\"4\" cols=\"20\"></textarea>" + 469720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block "</form></body></html>"); 479720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 489720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block private TestAdapterInputConnection mConnection; 499720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block private ImeAdapter mImeAdapter; 509720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 519720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block private ContentView mContentView; 529720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block private ContentViewCore mContentViewCore; 539720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block private TestCallbackHelperContainer mCallbackContainer; 549720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block private TestInputMethodManagerWrapper mInputMethodManagerWrapper; 559720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 569720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block @Override 579720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block public void setUp() throws Exception { 589720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block super.setUp(); 599720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 609720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block launchContentShellWithUrl(DATA_URL); 619720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading()); 629720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block mContentView = getContentView(); 639720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block mContentViewCore = getContentViewCore(); 649720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 659720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block mInputMethodManagerWrapper = new TestInputMethodManagerWrapper(mContentViewCore); 669720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block getImeAdapter().setInputMethodManagerWrapper(mInputMethodManagerWrapper); 679720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block assertEquals(0, mInputMethodManagerWrapper.getShowSoftInputCounter()); 689720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block mContentViewCore.setAdapterInputConnectionFactory( 699720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block new TestAdapterInputConnectionFactory()); 709720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 719720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block mCallbackContainer = new TestCallbackHelperContainer(getContentView()); 729720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block // TODO(aurimas) remove this wait once crbug.com/179511 is fixed. 739720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block assertWaitForPageScaleFactorMatch(2); 749720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block assertTrue(DOMUtils.waitForNonZeroNodeBounds( 759720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block mContentViewCore, "input_text")); 769720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block DOMUtils.clickNode(this, mContentView, "input_text"); 779720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block assertWaitForKeyboardStatus(true); 789720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 799720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block mConnection = (TestAdapterInputConnection) getAdapterInputConnection(); 809720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block mImeAdapter = getImeAdapter(); 819720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 829720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 0, "", 0, 0, -1, -1); 839720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block assertEquals(1, mInputMethodManagerWrapper.getShowSoftInputCounter()); 849720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block assertEquals(0, mInputMethodManagerWrapper.getEditorInfo().initialSelStart); 859720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block assertEquals(0, mInputMethodManagerWrapper.getEditorInfo().initialSelEnd); 869720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 879720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 889720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block @MediumTest 899720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block @Feature({"TextInput", "Main"}) 909720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block public void testKeyboardDismissedAfterClickingGo() throws Throwable { 919720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block setComposingText(mConnection, "hello", 1); 929720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 1, "hello", 5, 5, 0, 5); 939720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 949720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block performGo(getAdapterInputConnection(), mCallbackContainer); 959720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 969720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 2, "", 0, 0, -1, -1); 979720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block assertWaitForKeyboardStatus(false); 989720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 999720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 1009720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block @SmallTest 1019720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block @Feature({"TextInput", "Main"}) 1029720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block public void testGetTextUpdatesAfterEnteringText() throws Throwable { 1039720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block setComposingText(mConnection, "h", 1); 1049720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 1, "h", 1, 1, 0, 1); 1059720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block assertEquals(1, mInputMethodManagerWrapper.getShowSoftInputCounter()); 1069720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 1079720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block setComposingText(mConnection, "he", 1); 1089720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 2, "he", 2, 2, 0, 2); 1099720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block assertEquals(1, mInputMethodManagerWrapper.getShowSoftInputCounter()); 1109720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 1119720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block setComposingText(mConnection, "hel", 1); 1129720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 3, "hel", 3, 3, 0, 3); 1139720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block assertEquals(1, mInputMethodManagerWrapper.getShowSoftInputCounter()); 1149720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 1159720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block commitText(mConnection, "hel", 1); 1169720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 4, "hel", 3, 3, -1, -1); 1179720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block assertEquals(1, mInputMethodManagerWrapper.getShowSoftInputCounter()); 1189720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block } 1199720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block 1209720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block @SmallTest 1219720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block @Feature({"TextInput"}) 1229720d5f59b9c1f5d1b9ecbc9173dbcb71bd557beSteve Block public void testImeCopy() throws Exception { 123 commitText(mConnection, "hello", 1); 124 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 1, "hello", 5, 5, -1, -1); 125 126 setSelection(mConnection, 2, 5); 127 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 2, "hello", 2, 5, -1, -1); 128 129 copy(mImeAdapter); 130 assertClipboardContents(getActivity(), "llo"); 131 } 132 133 @SmallTest 134 @Feature({"TextInput"}) 135 public void testEnterTextAndRefocus() throws Exception { 136 commitText(mConnection, "hello", 1); 137 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 1, "hello", 5, 5, -1, -1); 138 139 DOMUtils.clickNode(this, mContentView, "input_radio"); 140 assertWaitForKeyboardStatus(false); 141 142 DOMUtils.clickNode(this, mContentView, "input_text"); 143 assertWaitForKeyboardStatus(true); 144 assertEquals(5, mInputMethodManagerWrapper.getEditorInfo().initialSelStart); 145 assertEquals(5, mInputMethodManagerWrapper.getEditorInfo().initialSelEnd); 146 } 147 148 @SmallTest 149 @Feature({"TextInput"}) 150 public void testImeCut() throws Exception { 151 commitText(mConnection, "snarful", 1); 152 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 1, "snarful", 7, 7, -1, -1); 153 154 setSelection(mConnection, 1, 5); 155 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 2, "snarful", 1, 5, -1, -1); 156 157 cut(mImeAdapter); 158 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 3, "sul", 1, 1, -1, -1); 159 160 assertClipboardContents(getActivity(), "narf"); 161 } 162 163 @SmallTest 164 @Feature({"TextInput"}) 165 public void testImePaste() throws Exception { 166 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 167 @Override 168 public void run() { 169 ClipboardManager clipboardManager = 170 (ClipboardManager) getActivity().getSystemService( 171 Context.CLIPBOARD_SERVICE); 172 clipboardManager.setPrimaryClip(ClipData.newPlainText("blarg", "blarg")); 173 } 174 }); 175 176 paste(mImeAdapter); 177 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 1, "blarg", 5, 5, -1, -1); 178 179 setSelection(mConnection, 3, 5); 180 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 2, "blarg", 3, 5, -1, -1); 181 182 paste(mImeAdapter); 183 // Paste is a two step process when there is a non-zero selection. 184 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 3, "bla", 3, 3, -1, -1); 185 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 4, "blablarg", 8, 8, -1, -1); 186 187 paste(mImeAdapter); 188 waitAndVerifyEditableCallback( 189 mConnection.mImeUpdateQueue, 5, "blablargblarg", 13, 13, -1, -1); 190 } 191 192 @SmallTest 193 @Feature({"TextInput"}) 194 public void testImeSelectAndUnSelectAll() throws Exception { 195 commitText(mConnection, "hello", 1); 196 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 1, "hello", 5, 5, -1, -1); 197 198 selectAll(mImeAdapter); 199 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 2, "hello", 0, 5, -1, -1); 200 201 unselect(mImeAdapter); 202 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 3, "", 0, 0, -1, -1); 203 204 assertWaitForKeyboardStatus(false); 205 } 206 207 @SmallTest 208 @Feature({"TextInput", "Main"}) 209 public void testShowImeIfNeeded() throws Throwable { 210 DOMUtils.focusNode(this, mContentViewCore, "input_radio"); 211 assertWaitForKeyboardStatus(false); 212 213 performShowImeIfNeeded(); 214 assertWaitForKeyboardStatus(false); 215 216 DOMUtils.focusNode(this, mContentViewCore, "input_text"); 217 assertWaitForKeyboardStatus(false); 218 219 performShowImeIfNeeded(); 220 assertWaitForKeyboardStatus(true); 221 } 222 223 @SmallTest 224 @Feature({"TextInput", "Main"}) 225 public void testFinishComposingText() throws Throwable { 226 // Focus the textarea. We need to do the following steps because we are focusing using JS. 227 DOMUtils.focusNode(this, mContentViewCore, "input_radio"); 228 assertWaitForKeyboardStatus(false); 229 DOMUtils.focusNode(this, mContentViewCore, "textarea"); 230 assertWaitForKeyboardStatus(false); 231 performShowImeIfNeeded(); 232 assertWaitForKeyboardStatus(true); 233 234 mConnection = (TestAdapterInputConnection) getAdapterInputConnection(); 235 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 0, "", 0, 0, -1, -1); 236 237 commitText(mConnection, "hllo", 1); 238 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 1, "hllo", 4, 4, -1, -1); 239 240 commitText(mConnection, " ", 1); 241 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 2, "hllo ", 5, 5, -1, -1); 242 243 setSelection(mConnection, 1, 1); 244 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 3, "hllo ", 1, 1, -1, -1); 245 246 setComposingRegion(mConnection, 0, 4); 247 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 4, "hllo ", 1, 1, 0, 4); 248 249 finishComposingText(mConnection); 250 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 5, "hllo ", 1, 1, -1, -1); 251 252 commitText(mConnection, "\n", 1); 253 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 6, "h\nllo ", 2, 2, -1, -1); 254 } 255 256 @SmallTest 257 @Feature({"TextInput", "Main"}) 258 public void testEnterKeyEventWhileComposingText() throws Throwable { 259 // Focus the textarea. We need to do the following steps because we are focusing using JS. 260 DOMUtils.focusNode(this, mContentViewCore, "input_radio"); 261 assertWaitForKeyboardStatus(false); 262 DOMUtils.focusNode(this, mContentViewCore, "textarea"); 263 assertWaitForKeyboardStatus(false); 264 performShowImeIfNeeded(); 265 assertWaitForKeyboardStatus(true); 266 267 mConnection = (TestAdapterInputConnection) getAdapterInputConnection(); 268 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 0, "", 0, 0, -1, -1); 269 270 setComposingText(mConnection, "hello", 1); 271 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 1, "hello", 5, 5, 0, 5); 272 273 getInstrumentation().runOnMainSync(new Runnable() { 274 @Override 275 public void run() { 276 mConnection.sendKeyEvent( 277 new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)); 278 mConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER)); 279 } 280 }); 281 282 // TODO(aurimas): remove this workaround when crbug.com/278584 is fixed. 283 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 2, "hello", 5, 5, -1, -1); 284 // The second new line is not a user visible/editable one, it is a side-effect of Blink 285 // using <br> internally. 286 waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 3, "hello\n\n", 6, 6, -1, -1); 287 } 288 289 private void performShowImeIfNeeded() { 290 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 291 @Override 292 public void run() { 293 mContentViewCore.showImeIfNeeded(); 294 } 295 }); 296 } 297 298 private void performGo(final AdapterInputConnection inputConnection, 299 TestCallbackHelperContainer testCallbackHelperContainer) throws Throwable { 300 handleBlockingCallbackAction( 301 testCallbackHelperContainer.getOnPageFinishedHelper(), 302 new Runnable() { 303 @Override 304 public void run() { 305 inputConnection.performEditorAction(EditorInfo.IME_ACTION_GO); 306 } 307 }); 308 } 309 310 private void assertWaitForKeyboardStatus(final boolean show) throws InterruptedException { 311 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { 312 @Override 313 public boolean isSatisfied() { 314 return show == getImeAdapter().mIsShowWithoutHideOutstanding && 315 (!show || getAdapterInputConnection() != null); 316 } 317 })); 318 } 319 320 private void waitAndVerifyEditableCallback(final ArrayList<TestImeState> states, 321 final int index, String text, int selectionStart, int selectionEnd, 322 int compositionStart, int compositionEnd) throws InterruptedException { 323 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { 324 @Override 325 public boolean isSatisfied() { 326 return states.size() > index; 327 } 328 })); 329 states.get(index).assertEqualState( 330 text, selectionStart, selectionEnd, compositionStart, compositionEnd); 331 } 332 333 private void assertClipboardContents(final Activity activity, final String expectedContents) 334 throws InterruptedException { 335 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { 336 @Override 337 public boolean isSatisfied() { 338 return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { 339 @Override 340 public Boolean call() throws Exception { 341 ClipboardManager clipboardManager = 342 (ClipboardManager) activity.getSystemService( 343 Context.CLIPBOARD_SERVICE); 344 ClipData clip = clipboardManager.getPrimaryClip(); 345 return clip != null && clip.getItemCount() == 1 346 && TextUtils.equals(clip.getItemAt(0).getText(), expectedContents); 347 } 348 }); 349 } 350 })); 351 } 352 353 private ImeAdapter getImeAdapter() { 354 return mContentViewCore.getImeAdapterForTest(); 355 } 356 357 private AdapterInputConnection getAdapterInputConnection() { 358 return mContentViewCore.getInputConnectionForTest(); 359 } 360 361 private void copy(final ImeAdapter adapter) { 362 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 363 @Override 364 public void run() { 365 adapter.copy(); 366 } 367 }); 368 } 369 370 private void cut(final ImeAdapter adapter) { 371 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 372 @Override 373 public void run() { 374 adapter.cut(); 375 } 376 }); 377 } 378 379 private void paste(final ImeAdapter adapter) { 380 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 381 @Override 382 public void run() { 383 adapter.paste(); 384 } 385 }); 386 } 387 388 private void selectAll(final ImeAdapter adapter) { 389 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 390 @Override 391 public void run() { 392 adapter.selectAll(); 393 } 394 }); 395 } 396 397 private void unselect(final ImeAdapter adapter) { 398 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 399 @Override 400 public void run() { 401 adapter.unselect(); 402 } 403 }); 404 } 405 406 private void commitText(final AdapterInputConnection connection, final CharSequence text, 407 final int newCursorPosition) { 408 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 409 @Override 410 public void run() { 411 connection.commitText(text, newCursorPosition); 412 } 413 }); 414 } 415 416 private void setSelection(final AdapterInputConnection connection, final int start, 417 final int end) { 418 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 419 @Override 420 public void run() { 421 connection.setSelection(start, end); 422 } 423 }); 424 } 425 426 private void setComposingRegion(final AdapterInputConnection connection, final int start, 427 final int end) { 428 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 429 @Override 430 public void run() { 431 connection.setComposingRegion(start, end); 432 } 433 }); 434 } 435 436 private void setComposingText(final AdapterInputConnection connection, final CharSequence text, 437 final int newCursorPosition) { 438 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 439 @Override 440 public void run() { 441 connection.setComposingText(text, newCursorPosition); 442 } 443 }); 444 } 445 446 private void finishComposingText(final AdapterInputConnection connection) { 447 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 448 @Override 449 public void run() { 450 connection.finishComposingText(); 451 } 452 }); 453 } 454 455 private static class TestAdapterInputConnectionFactory extends 456 ImeAdapter.AdapterInputConnectionFactory { 457 @Override 458 public AdapterInputConnection get(View view, ImeAdapter imeAdapter, 459 Editable editable, EditorInfo outAttrs) { 460 return new TestAdapterInputConnection(view, imeAdapter, editable, outAttrs); 461 } 462 } 463 464 private static class TestAdapterInputConnection extends AdapterInputConnection { 465 private final ArrayList<TestImeState> mImeUpdateQueue = new ArrayList<TestImeState>(); 466 467 public TestAdapterInputConnection(View view, ImeAdapter imeAdapter, 468 Editable editable, EditorInfo outAttrs) { 469 super(view, imeAdapter, editable, outAttrs); 470 } 471 472 @Override 473 public void updateState(String text, int selectionStart, int selectionEnd, 474 int compositionStart, int compositionEnd, boolean requiredAck) { 475 mImeUpdateQueue.add(new TestImeState(text, selectionStart, selectionEnd, 476 compositionStart, compositionEnd)); 477 super.updateState(text, selectionStart, selectionEnd, compositionStart, 478 compositionEnd, requiredAck); 479 } 480 } 481 482 private static class TestImeState { 483 private final String mText; 484 private final int mSelectionStart; 485 private final int mSelectionEnd; 486 private final int mCompositionStart; 487 private final int mCompositionEnd; 488 489 public TestImeState(String text, int selectionStart, int selectionEnd, 490 int compositionStart, int compositionEnd) { 491 mText = text; 492 mSelectionStart = selectionStart; 493 mSelectionEnd = selectionEnd; 494 mCompositionStart = compositionStart; 495 mCompositionEnd = compositionEnd; 496 } 497 498 public void assertEqualState(String text, int selectionStart, int selectionEnd, 499 int compositionStart, int compositionEnd) { 500 assertEquals("Text did not match", text, mText); 501 assertEquals("Selection start did not match", selectionStart, mSelectionStart); 502 assertEquals("Selection end did not match", selectionEnd, mSelectionEnd); 503 assertEquals("Composition start did not match", compositionStart, mCompositionStart); 504 assertEquals("Composition end did not match", compositionEnd, mCompositionEnd); 505 } 506 } 507} 508