TextViewActivityTest.java revision 6eecdc934c6050d67a639116cde600c09e5b76bd
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17package android.widget; 18 19import static android.widget.espresso.CustomViewActions.longPressAtRelativeCoordinates; 20import static android.widget.espresso.DragHandleUtils.assertNoSelectionHandles; 21import static android.widget.espresso.DragHandleUtils.onHandleView; 22import static android.widget.espresso.TextViewActions.clickOnTextAtIndex; 23import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText; 24import static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex; 25import static android.widget.espresso.TextViewActions.dragHandle; 26import static android.widget.espresso.TextViewActions.Handle; 27import static android.widget.espresso.TextViewActions.longPressAndDragOnText; 28import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex; 29import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex; 30import static android.widget.espresso.TextViewAssertions.hasSelection; 31import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarItemIndex; 32import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed; 33import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsNotDisplayed; 34import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem; 35import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem; 36import static android.widget.espresso.FloatingToolbarEspressoUtils.clickFloatingToolbarItem; 37import static android.widget.espresso.FloatingToolbarEspressoUtils.sleepForFloatingToolbarPopup; 38import static android.support.test.espresso.Espresso.onView; 39import static android.support.test.espresso.action.ViewActions.click; 40import static android.support.test.espresso.action.ViewActions.longClick; 41import static android.support.test.espresso.action.ViewActions.pressKey; 42import static android.support.test.espresso.action.ViewActions.replaceText; 43import static android.support.test.espresso.assertion.ViewAssertions.matches; 44import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; 45import static android.support.test.espresso.matcher.ViewMatchers.withId; 46import static android.support.test.espresso.matcher.ViewMatchers.withText; 47import static org.hamcrest.Matchers.anyOf; 48import static org.hamcrest.Matchers.is; 49 50import android.view.ActionMode; 51import android.view.Menu; 52import android.view.MenuItem; 53import android.view.textclassifier.TextClassificationManager; 54import android.view.textclassifier.TextClassifier; 55import android.widget.espresso.CustomViewActions.RelativeCoordinatesProvider; 56 57import android.support.test.espresso.action.EspressoKey; 58import android.test.ActivityInstrumentationTestCase2; 59import android.test.suitebuilder.annotation.MediumTest; 60import android.text.Selection; 61import android.text.Spannable; 62import android.text.InputType; 63import android.view.KeyEvent; 64 65import com.android.frameworks.coretests.R; 66 67/** 68 * Tests the TextView widget from an Activity 69 */ 70@MediumTest 71public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextViewActivity>{ 72 73 public TextViewActivityTest() { 74 super(TextViewActivity.class); 75 } 76 77 @Override 78 public void setUp() throws Exception { 79 super.setUp(); 80 getActivity().getSystemService(TextClassificationManager.class) 81 .setTextClassifier(TextClassifier.NO_OP); 82 } 83 84 public void testTypedTextIsOnScreen() throws Exception { 85 final String helloWorld = "Hello world!"; 86 // We use replaceText instead of typeTextIntoFocusedView to input text to avoid 87 // unintentional interactions with software keyboard. 88 onView(withId(R.id.textview)).perform(replaceText(helloWorld)); 89 90 onView(withId(R.id.textview)).check(matches(withText(helloWorld))); 91 } 92 93 public void testPositionCursorAtTextAtIndex() throws Exception { 94 final String helloWorld = "Hello world!"; 95 onView(withId(R.id.textview)).perform(replaceText(helloWorld)); 96 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("world"))); 97 98 // Delete text at specified index and see if we got the right one. 99 onView(withId(R.id.textview)).perform(pressKey(KeyEvent.KEYCODE_FORWARD_DEL)); 100 onView(withId(R.id.textview)).check(matches(withText("Hello orld!"))); 101 } 102 103 public void testPositionCursorAtTextAtIndex_arabic() throws Exception { 104 // Arabic text. The expected cursorable boundary is 105 // | \u0623 \u064F | \u067A | \u0633 \u0652 | 106 final String text = "\u0623\u064F\u067A\u0633\u0652"; 107 onView(withId(R.id.textview)).perform(replaceText(text)); 108 109 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0)); 110 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0)); 111 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1)); 112 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2)))); 113 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2)); 114 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2)); 115 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(3)); 116 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(3)); 117 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(4)); 118 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(3), is(5)))); 119 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(5)); 120 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(5)); 121 } 122 123 public void testPositionCursorAtTextAtIndex_devanagari() throws Exception { 124 // Devanagari text. The expected cursorable boundary is | \u0915 \u093E | 125 final String text = "\u0915\u093E"; 126 onView(withId(R.id.textview)).perform(replaceText(text)); 127 128 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0)); 129 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0)); 130 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1)); 131 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2)))); 132 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2)); 133 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2)); 134 } 135 136 public void testLongPressToSelect() throws Exception { 137 final String helloWorld = "Hello Kirk!"; 138 onView(withId(R.id.textview)).perform(click()); 139 onView(withId(R.id.textview)).perform(replaceText(helloWorld)); 140 onView(withId(R.id.textview)).perform( 141 longPressOnTextAtIndex(helloWorld.indexOf("Kirk"))); 142 143 onView(withId(R.id.textview)).check(hasSelection("Kirk")); 144 } 145 146 public void testLongPressEmptySpace() throws Exception { 147 final String helloWorld = "Hello big round sun!"; 148 onView(withId(R.id.textview)).perform(replaceText(helloWorld)); 149 // Move cursor somewhere else 150 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("big"))); 151 // Long-press at end of line. 152 onView(withId(R.id.textview)).perform(longPressAtRelativeCoordinates( 153 RelativeCoordinatesProvider.HorizontalReference.RIGHT, -5, 154 RelativeCoordinatesProvider.VerticalReference.CENTER, 0)); 155 156 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(helloWorld.length())); 157 } 158 159 public void testLongPressAndDragToSelect() throws Exception { 160 final String helloWorld = "Hello little handsome boy!"; 161 onView(withId(R.id.textview)).perform(replaceText(helloWorld)); 162 onView(withId(R.id.textview)).perform( 163 longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!"))); 164 165 onView(withId(R.id.textview)).check(hasSelection("little handsome")); 166 } 167 168 public void testLongPressAndDragToSelect_emoji() throws Exception { 169 final String text = "\uD83D\uDE00\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03"; 170 onView(withId(R.id.textview)).perform(replaceText(text)); 171 172 onView(withId(R.id.textview)).perform(longPressAndDragOnText(4, 6)); 173 onView(withId(R.id.textview)).check(hasSelection("\uD83D\uDE02")); 174 175 onView(withId(R.id.textview)).perform(click()); 176 177 onView(withId(R.id.textview)).perform(longPressAndDragOnText(4, 2)); 178 onView(withId(R.id.textview)).check(hasSelection("\uD83D\uDE01")); 179 } 180 181 public void testDragAndDrop() throws Exception { 182 final String text = "abc def ghi."; 183 onView(withId(R.id.textview)).perform(replaceText(text)); 184 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("e"))); 185 186 onView(withId(R.id.textview)).perform( 187 longPressAndDragOnText(text.indexOf("e"), text.length())); 188 189 onView(withId(R.id.textview)).check(matches(withText("abc ghi.def"))); 190 onView(withId(R.id.textview)).check(hasSelection("")); 191 assertNoSelectionHandles(); 192 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length())); 193 194 // Test undo returns to the original state. 195 onView(withId(R.id.textview)).perform(pressKey( 196 (new EspressoKey.Builder()).withCtrlPressed(true).withKeyCode(KeyEvent.KEYCODE_Z) 197 .build())); 198 onView(withId(R.id.textview)).check(matches(withText(text))); 199 } 200 201 public void testDoubleTapToSelect() throws Exception { 202 final String helloWorld = "Hello SuetYi!"; 203 onView(withId(R.id.textview)).perform(replaceText(helloWorld)); 204 205 onView(withId(R.id.textview)).perform( 206 doubleClickOnTextAtIndex(helloWorld.indexOf("SuetYi"))); 207 208 onView(withId(R.id.textview)).check(hasSelection("SuetYi")); 209 } 210 211 public void testDoubleTapAndDragToSelect() throws Exception { 212 final String helloWorld = "Hello young beautiful girl!"; 213 onView(withId(R.id.textview)).perform(replaceText(helloWorld)); 214 onView(withId(R.id.textview)).perform( 215 doubleTapAndDragOnText(helloWorld.indexOf("young"), helloWorld.indexOf(" girl!"))); 216 217 onView(withId(R.id.textview)).check(hasSelection("young beautiful")); 218 } 219 220 public void testDoubleTapAndDragToSelect_multiLine() throws Exception { 221 final String helloWorld = "abcd\n" + "efg\n" + "hijklm\n" + "nop"; 222 onView(withId(R.id.textview)).perform(replaceText(helloWorld)); 223 onView(withId(R.id.textview)).perform( 224 doubleTapAndDragOnText(helloWorld.indexOf("m"), helloWorld.indexOf("a"))); 225 onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijklm")); 226 } 227 228 public void testSelectBackwordsByTouch() throws Exception { 229 final String helloWorld = "Hello king of the Jungle!"; 230 onView(withId(R.id.textview)).perform(replaceText(helloWorld)); 231 onView(withId(R.id.textview)).perform( 232 doubleTapAndDragOnText(helloWorld.indexOf(" Jungle!"), helloWorld.indexOf("king"))); 233 234 onView(withId(R.id.textview)).check(hasSelection("king of the")); 235 } 236 237 public void testToolbarAppearsAfterSelection() throws Exception { 238 final String text = "Toolbar appears after selection."; 239 assertFloatingToolbarIsNotDisplayed(); 240 onView(withId(R.id.textview)).perform(replaceText(text)); 241 onView(withId(R.id.textview)).perform( 242 longPressOnTextAtIndex(text.indexOf("appears"))); 243 244 sleepForFloatingToolbarPopup(); 245 assertFloatingToolbarIsDisplayed(); 246 247 final String text2 = "Toolbar disappears after typing text."; 248 onView(withId(R.id.textview)).perform(replaceText(text2)); 249 sleepForFloatingToolbarPopup(); 250 assertFloatingToolbarIsNotDisplayed(); 251 } 252 253 public void testToolbarAppearsAfterSelection_withFirstStringLtrAlgorithmAndRtlHint() 254 throws Exception { 255 // after the hint layout change, the floating toolbar was not visible in the case below 256 // this test tests that the floating toolbar is displayed on the screen and is visible to 257 // user. 258 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 259 textView.post(new Runnable() { 260 @Override 261 public void run() { 262 textView.setTextDirection(TextView.TEXT_DIRECTION_FIRST_STRONG_LTR); 263 textView.setInputType(InputType.TYPE_CLASS_TEXT); 264 textView.setSingleLine(true); 265 textView.setHint("الروبوت"); 266 } 267 }); 268 getInstrumentation().waitForIdleSync(); 269 270 onView(withId(R.id.textview)).perform(replaceText("test")); 271 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(1)); 272 clickFloatingToolbarItem( 273 getActivity().getString(com.android.internal.R.string.cut)); 274 onView(withId(R.id.textview)).perform(longClick()); 275 sleepForFloatingToolbarPopup(); 276 277 assertFloatingToolbarIsDisplayed(); 278 } 279 280 public void testToolbarAndInsertionHandle() throws Exception { 281 final String text = "text"; 282 onView(withId(R.id.textview)).perform(replaceText(text)); 283 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length())); 284 assertFloatingToolbarIsNotDisplayed(); 285 286 onHandleView(com.android.internal.R.id.insertion_handle).perform(click()); 287 sleepForFloatingToolbarPopup(); 288 assertFloatingToolbarIsDisplayed(); 289 290 assertFloatingToolbarContainsItem( 291 getActivity().getString(com.android.internal.R.string.selectAll)); 292 assertFloatingToolbarDoesNotContainItem( 293 getActivity().getString(com.android.internal.R.string.copy)); 294 assertFloatingToolbarDoesNotContainItem( 295 getActivity().getString(com.android.internal.R.string.cut)); 296 } 297 298 public void testToolbarAndSelectionHandle() throws Exception { 299 final String text = "abcd efg hijk"; 300 onView(withId(R.id.textview)).perform(replaceText(text)); 301 302 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("f"))); 303 sleepForFloatingToolbarPopup(); 304 assertFloatingToolbarIsDisplayed(); 305 306 assertFloatingToolbarContainsItem( 307 getActivity().getString(com.android.internal.R.string.selectAll)); 308 assertFloatingToolbarContainsItem( 309 getActivity().getString(com.android.internal.R.string.copy)); 310 assertFloatingToolbarContainsItem( 311 getActivity().getString(com.android.internal.R.string.cut)); 312 313 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 314 onHandleView(com.android.internal.R.id.selection_start_handle) 315 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a'))); 316 sleepForFloatingToolbarPopup(); 317 assertFloatingToolbarIsDisplayed(); 318 319 onHandleView(com.android.internal.R.id.selection_end_handle) 320 .perform(dragHandle(textView, Handle.SELECTION_END, text.length())); 321 sleepForFloatingToolbarPopup(); 322 assertFloatingToolbarIsDisplayed(); 323 324 assertFloatingToolbarDoesNotContainItem( 325 getActivity().getString(com.android.internal.R.string.selectAll)); 326 assertFloatingToolbarContainsItem( 327 getActivity().getString(com.android.internal.R.string.copy)); 328 assertFloatingToolbarContainsItem( 329 getActivity().getString(com.android.internal.R.string.cut)); 330 } 331 332 public void testInsertionHandle() throws Exception { 333 final String text = "abcd efg hijk "; 334 onView(withId(R.id.textview)).perform(replaceText(text)); 335 336 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length())); 337 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length())); 338 339 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 340 341 onHandleView(com.android.internal.R.id.insertion_handle) 342 .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a'))); 343 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a"))); 344 345 onHandleView(com.android.internal.R.id.insertion_handle) 346 .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f'))); 347 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f"))); 348 } 349 350 public void testInsertionHandle_multiLine() throws Exception { 351 final String text = "abcd\n" + "efg\n" + "hijk\n"; 352 onView(withId(R.id.textview)).perform(replaceText(text)); 353 354 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length())); 355 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length())); 356 357 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 358 359 onHandleView(com.android.internal.R.id.insertion_handle) 360 .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a'))); 361 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a"))); 362 363 onHandleView(com.android.internal.R.id.insertion_handle) 364 .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f'))); 365 onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f"))); 366 } 367 368 public void testSelectionHandles() throws Exception { 369 final String text = "abcd efg hijk lmn"; 370 onView(withId(R.id.textview)).perform(replaceText(text)); 371 372 assertNoSelectionHandles(); 373 374 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f'))); 375 376 onHandleView(com.android.internal.R.id.selection_start_handle) 377 .check(matches(isDisplayed())); 378 onHandleView(com.android.internal.R.id.selection_end_handle) 379 .check(matches(isDisplayed())); 380 381 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 382 onHandleView(com.android.internal.R.id.selection_start_handle) 383 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a'))); 384 onView(withId(R.id.textview)).check(hasSelection("abcd efg")); 385 386 onHandleView(com.android.internal.R.id.selection_end_handle) 387 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('k') + 1)); 388 onView(withId(R.id.textview)).check(hasSelection("abcd efg hijk")); 389 } 390 391 public void testSelectionHandles_bidi() throws Exception { 392 final String text = "abc \u0621\u0622\u0623 def"; 393 onView(withId(R.id.textview)).perform(replaceText(text)); 394 395 assertNoSelectionHandles(); 396 397 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('\u0622'))); 398 399 onHandleView(com.android.internal.R.id.selection_start_handle) 400 .check(matches(isDisplayed())); 401 onHandleView(com.android.internal.R.id.selection_end_handle) 402 .check(matches(isDisplayed())); 403 404 onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623")); 405 406 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 407 onHandleView(com.android.internal.R.id.selection_start_handle) 408 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('f'))); 409 onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623")); 410 411 onHandleView(com.android.internal.R.id.selection_end_handle) 412 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a'))); 413 onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623")); 414 415 onHandleView(com.android.internal.R.id.selection_start_handle) 416 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0623'), 417 false)); 418 onView(withId(R.id.textview)).check(hasSelection("\u0623")); 419 420 onHandleView(com.android.internal.R.id.selection_start_handle) 421 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0621'), 422 false)); 423 onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623")); 424 425 onHandleView(com.android.internal.R.id.selection_start_handle) 426 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a'))); 427 onView(withId(R.id.textview)).check(hasSelection("abc \u0621\u0622\u0623")); 428 429 onHandleView(com.android.internal.R.id.selection_end_handle) 430 .perform(dragHandle(textView, Handle.SELECTION_END, text.length())); 431 onView(withId(R.id.textview)).check(hasSelection("abc \u0621\u0622\u0623 def")); 432 } 433 434 public void testSelectionHandles_multiLine() throws Exception { 435 final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr"; 436 onView(withId(R.id.textview)).perform(replaceText(text)); 437 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i'))); 438 439 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 440 onHandleView(com.android.internal.R.id.selection_start_handle) 441 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('e'))); 442 onView(withId(R.id.textview)).check(hasSelection("efg\nhijk")); 443 444 onHandleView(com.android.internal.R.id.selection_start_handle) 445 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a'))); 446 onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk")); 447 448 onHandleView(com.android.internal.R.id.selection_end_handle) 449 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('n') + 1)); 450 onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk\nlmn")); 451 452 onHandleView(com.android.internal.R.id.selection_end_handle) 453 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('r') + 1)); 454 onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk\nlmn\nopqr")); 455 } 456 457 public void testSelectionHandles_multiLine_rtl() throws Exception { 458 // Arabic text. 459 final String text = "\u062A\u062B\u062C\n" + "\u062D\u062E\u062F\n" 460 + "\u0630\u0631\u0632\n" + "\u0633\u0634\u0635\n" + "\u0636\u0637\u0638\n" 461 + "\u0639\u063A\u063B"; 462 onView(withId(R.id.textview)).perform(replaceText(text)); 463 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('\u0634'))); 464 465 final TextView textView = (TextView)getActivity().findViewById(R.id.textview); 466 onHandleView(com.android.internal.R.id.selection_start_handle) 467 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u062E'))); 468 onView(withId(R.id.textview)).check(hasSelection( 469 text.substring(text.indexOf('\u062D'), text.indexOf('\u0635') + 1))); 470 471 onHandleView(com.android.internal.R.id.selection_start_handle) 472 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u062A'))); 473 onView(withId(R.id.textview)).check(hasSelection( 474 text.substring(text.indexOf('\u062A'), text.indexOf('\u0635') + 1))); 475 476 onHandleView(com.android.internal.R.id.selection_end_handle) 477 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('\u0638'))); 478 onView(withId(R.id.textview)).check(hasSelection( 479 text.substring(text.indexOf('\u062A'), text.indexOf('\u0638') + 1))); 480 481 onHandleView(com.android.internal.R.id.selection_end_handle) 482 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('\u063B'))); 483 onView(withId(R.id.textview)).check(hasSelection(text)); 484 } 485 486 487 public void testSelectionHandles_doesNotPassAnotherHandle() throws Exception { 488 final String text = "abcd efg hijk lmn"; 489 onView(withId(R.id.textview)).perform(replaceText(text)); 490 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f'))); 491 492 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 493 onHandleView(com.android.internal.R.id.selection_start_handle) 494 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('l'))); 495 onView(withId(R.id.textview)).check(hasSelection("g")); 496 497 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f'))); 498 onHandleView(com.android.internal.R.id.selection_end_handle) 499 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a'))); 500 onView(withId(R.id.textview)).check(hasSelection("e")); 501 } 502 503 public void testSelectionHandles_doesNotPassAnotherHandle_multiLine() throws Exception { 504 final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr"; 505 onView(withId(R.id.textview)).perform(replaceText(text)); 506 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i'))); 507 508 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 509 onHandleView(com.android.internal.R.id.selection_start_handle) 510 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('r') + 1)); 511 onView(withId(R.id.textview)).check(hasSelection("k")); 512 513 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i'))); 514 onHandleView(com.android.internal.R.id.selection_end_handle) 515 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a'))); 516 onView(withId(R.id.textview)).check(hasSelection("h")); 517 } 518 519 public void testSelectionHandles_snapToWordBoundary() throws Exception { 520 final String text = "abcd efg hijk lmn opqr"; 521 onView(withId(R.id.textview)).perform(replaceText(text)); 522 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i'))); 523 524 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 525 526 onHandleView(com.android.internal.R.id.selection_start_handle) 527 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('f'))); 528 onView(withId(R.id.textview)).check(hasSelection("efg hijk")); 529 530 onHandleView(com.android.internal.R.id.selection_start_handle) 531 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('d') + 1)); 532 onView(withId(R.id.textview)).check(hasSelection("efg hijk")); 533 534 535 onHandleView(com.android.internal.R.id.selection_start_handle) 536 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('c'))); 537 onView(withId(R.id.textview)).check(hasSelection("abcd efg hijk")); 538 539 onHandleView(com.android.internal.R.id.selection_start_handle) 540 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('d'))); 541 onView(withId(R.id.textview)).check(hasSelection("d efg hijk")); 542 543 onHandleView(com.android.internal.R.id.selection_start_handle) 544 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('b'))); 545 onView(withId(R.id.textview)).check(hasSelection("bcd efg hijk")); 546 547 onView(withId(R.id.textview)).perform(click()); 548 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i'))); 549 550 onHandleView(com.android.internal.R.id.selection_end_handle) 551 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('n'))); 552 onView(withId(R.id.textview)).check(hasSelection("hijk lmn")); 553 554 onHandleView(com.android.internal.R.id.selection_end_handle) 555 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('o'))); 556 onView(withId(R.id.textview)).check(hasSelection("hijk lmn")); 557 558 onHandleView(com.android.internal.R.id.selection_end_handle) 559 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('q'))); 560 onView(withId(R.id.textview)).check(hasSelection("hijk lmn opqr")); 561 562 onHandleView(com.android.internal.R.id.selection_end_handle) 563 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('p'))); 564 onView(withId(R.id.textview)).check(hasSelection("hijk lmn o")); 565 566 onHandleView(com.android.internal.R.id.selection_end_handle) 567 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('r'))); 568 onView(withId(R.id.textview)).check(hasSelection("hijk lmn opq")); 569 } 570 571 public void testSelectionHandles_snapToWordBoundary_multiLine() throws Exception { 572 final String text = "abcd efg\n" + "hijk lmn\n" + "opqr stu"; 573 onView(withId(R.id.textview)).perform(replaceText(text)); 574 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('m'))); 575 576 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 577 578 onHandleView(com.android.internal.R.id.selection_start_handle) 579 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('c'))); 580 onView(withId(R.id.textview)).check(hasSelection("abcd efg\nhijk lmn")); 581 582 onHandleView(com.android.internal.R.id.selection_start_handle) 583 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('g'))); 584 onView(withId(R.id.textview)).check(hasSelection("g\nhijk lmn")); 585 586 onHandleView(com.android.internal.R.id.selection_start_handle) 587 .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('m'))); 588 onView(withId(R.id.textview)).check(hasSelection("lmn")); 589 590 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('i'))); 591 592 onHandleView(com.android.internal.R.id.selection_end_handle) 593 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('u'))); 594 onView(withId(R.id.textview)).check(hasSelection("hijk lmn\nopqr stu")); 595 596 onHandleView(com.android.internal.R.id.selection_end_handle) 597 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('p'))); 598 onView(withId(R.id.textview)).check(hasSelection("hijk lmn\no")); 599 600 onHandleView(com.android.internal.R.id.selection_end_handle) 601 .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('i'))); 602 onView(withId(R.id.textview)).check(hasSelection("hijk")); 603 } 604 605 public void testSetSelectionAndActionMode() throws Exception { 606 final String text = "abc def"; 607 onView(withId(R.id.textview)).perform(replaceText(text)); 608 609 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 610 assertFloatingToolbarIsNotDisplayed(); 611 textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0, 3)); 612 getInstrumentation().waitForIdleSync(); 613 sleepForFloatingToolbarPopup(); 614 // Don't automatically start action mode. 615 assertFloatingToolbarIsNotDisplayed(); 616 // Make sure that "Select All" is included in the selection action mode when the entire text 617 // is not selected. 618 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('e'))); 619 sleepForFloatingToolbarPopup(); 620 assertFloatingToolbarIsDisplayed(); 621 // Changing the selection range by API should not interrupt the selection action mode. 622 textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0, 3)); 623 getInstrumentation().waitForIdleSync(); 624 sleepForFloatingToolbarPopup(); 625 assertFloatingToolbarIsDisplayed(); 626 assertFloatingToolbarContainsItem( 627 getActivity().getString(com.android.internal.R.string.selectAll)); 628 // Make sure that "Select All" is no longer included when the entire text is selected by 629 // API. 630 textView.post( 631 () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length())); 632 getInstrumentation().waitForIdleSync(); 633 sleepForFloatingToolbarPopup(); 634 assertFloatingToolbarIsDisplayed(); 635 assertFloatingToolbarDoesNotContainItem( 636 getActivity().getString(com.android.internal.R.string.selectAll)); 637 // Make sure that shrinking the selection range to cursor (an empty range) by API 638 // terminates selection action mode and does not trigger the insertion action mode. 639 textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0)); 640 getInstrumentation().waitForIdleSync(); 641 sleepForFloatingToolbarPopup(); 642 assertFloatingToolbarIsNotDisplayed(); 643 // Make sure that user click can trigger the insertion action mode. 644 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length())); 645 onHandleView(com.android.internal.R.id.insertion_handle).perform(click()); 646 sleepForFloatingToolbarPopup(); 647 assertFloatingToolbarIsDisplayed(); 648 // Make sure that an existing insertion action mode keeps alive after the insertion point is 649 // moved by API. 650 textView.post(() -> Selection.setSelection((Spannable) textView.getText(), 0)); 651 getInstrumentation().waitForIdleSync(); 652 sleepForFloatingToolbarPopup(); 653 assertFloatingToolbarIsDisplayed(); 654 assertFloatingToolbarDoesNotContainItem( 655 getActivity().getString(com.android.internal.R.string.copy)); 656 // Make sure that selection action mode is started after selection is created by API when 657 // insertion action mode is active. 658 textView.post( 659 () -> Selection.setSelection((Spannable) textView.getText(), 1, text.length())); 660 getInstrumentation().waitForIdleSync(); 661 sleepForFloatingToolbarPopup(); 662 assertFloatingToolbarIsDisplayed(); 663 assertFloatingToolbarContainsItem( 664 getActivity().getString(com.android.internal.R.string.copy)); 665 } 666 667 public void testTransientState() throws Exception { 668 final String text = "abc def"; 669 onView(withId(R.id.textview)).perform(replaceText(text)); 670 671 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 672 assertFalse(textView.hasTransientState()); 673 674 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('b'))); 675 // hasTransientState should return true when user generated selection is active. 676 assertTrue(textView.hasTransientState()); 677 onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.indexOf('d'))); 678 // hasTransientState should return false as the selection has been cleared. 679 assertFalse(textView.hasTransientState()); 680 textView.post( 681 () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length())); 682 getInstrumentation().waitForIdleSync(); 683 // hasTransientState should return false when selection is created by API. 684 assertFalse(textView.hasTransientState()); 685 } 686 687 public void testAssistItemIsAtIndexZero() throws Exception { 688 getActivity().getSystemService(TextClassificationManager.class).setTextClassifier(null); 689 final TextView textView = (TextView) getActivity().findViewById(R.id.textview); 690 textView.post(() -> textView.setCustomSelectionActionModeCallback( 691 new ActionMode.Callback() { 692 @Override 693 public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { 694 // Create another item at order position 0 to confirm that it will never be 695 // placed before the textAssist item. 696 menu.add(Menu.NONE, 0 /* id */, 0 /* order */, "Test"); 697 return true; 698 } 699 700 @Override 701 public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { 702 return true; 703 } 704 705 @Override 706 public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { 707 return false; 708 } 709 710 @Override 711 public void onDestroyActionMode(ActionMode actionMode) {} 712 })); 713 final String text = "droid@android.com"; 714 715 onView(withId(R.id.textview)).perform(replaceText(text)); 716 onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('@'))); 717 sleepForFloatingToolbarPopup(); 718 assertFloatingToolbarItemIndex(android.R.id.textAssist, 0); 719 } 720} 721