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