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