TextViewActivityTest.java revision 15485b8cae00133ac46a9b36db8e228aa8e73741
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.FloatingToolbarEspressoUtils.onFloatingToolBarItem;
24import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
25import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
26import static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex;
27import static android.widget.espresso.TextViewActions.dragHandle;
28import static android.widget.espresso.TextViewActions.Handle;
29import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
30import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
31import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
32import static android.widget.espresso.TextViewAssertions.hasSelection;
33import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed;
34import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsNotDisplayed;
35import static android.widget.espresso.FloatingToolbarEspressoUtils.sleepForFloatingToolbarPopup;
36import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem;
37import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem;
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() {
73        getActivity();
74    }
75
76    @SmallTest
77    public void testTypedTextIsOnScreen() throws Exception {
78        final String helloWorld = "Hello world!";
79        onView(withId(R.id.textview)).perform(click());
80        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
81
82        onView(withId(R.id.textview)).check(matches(withText(helloWorld)));
83    }
84
85    @SmallTest
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    @SmallTest
98    public void testPositionCursorAtTextAtIndex_arabic() throws Exception {
99        // Arabic text. The expected cursorable boundary is
100        // | \u0623 \u064F | \u067A | \u0633 \u0652 |
101        final String text = "\u0623\u064F\u067A\u0633\u0652";
102        onView(withId(R.id.textview)).perform(click());
103        onView(withId(R.id.textview)).perform(replaceText(text));
104
105        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
106        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
107        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1));
108        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2))));
109        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2));
110        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2));
111        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(3));
112        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(3));
113        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(4));
114        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(3), is(5))));
115        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(5));
116        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(5));
117    }
118
119    @SmallTest
120    public void testPositionCursorAtTextAtIndex_devanagari() throws Exception {
121        // Devanagari text. The expected cursorable boundary is | \u0915 \u093E |
122        final String text = "\u0915\u093E";
123        onView(withId(R.id.textview)).perform(click());
124        onView(withId(R.id.textview)).perform(replaceText(text));
125
126        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
127        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
128        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1));
129        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2))));
130        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2));
131        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2));
132    }
133
134    @SmallTest
135    public void testLongPressToSelect() throws Exception {
136        final String helloWorld = "Hello Kirk!";
137        onView(withId(R.id.textview)).perform(click());
138        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
139        onView(withId(R.id.textview)).perform(
140                longPressOnTextAtIndex(helloWorld.indexOf("Kirk")));
141
142        onView(withId(R.id.textview)).check(hasSelection("Kirk"));
143    }
144
145    @SmallTest
146    public void testLongPressEmptySpace() throws Exception {
147        final String helloWorld = "Hello big round sun!";
148        onView(withId(R.id.textview)).perform(click());
149        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
150        // Move cursor somewhere else
151        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("big")));
152        // Long-press at end of line.
153        onView(withId(R.id.textview)).perform(longPressAtRelativeCoordinates(
154                RelativeCoordinatesProvider.HorizontalReference.RIGHT, -5,
155                RelativeCoordinatesProvider.VerticalReference.CENTER, 0));
156
157        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(helloWorld.length()));
158    }
159
160    @SmallTest
161    public void testLongPressAndDragToSelect() throws Exception {
162        final String helloWorld = "Hello little handsome boy!";
163        onView(withId(R.id.textview)).perform(click());
164        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
165        onView(withId(R.id.textview)).perform(
166                longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!")));
167
168        onView(withId(R.id.textview)).check(hasSelection("little handsome"));
169    }
170
171    @SmallTest
172    public void testDragAndDrop() throws Exception {
173        final String text = "abc def ghi.";
174        onView(withId(R.id.textview)).perform(click());
175        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
176        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("e")));
177
178        onView(withId(R.id.textview)).perform(
179                longPressAndDragOnText(text.indexOf("e"), text.length()));
180
181        onView(withId(R.id.textview)).check(matches(withText("abc ghi.def")));
182        onView(withId(R.id.textview)).check(hasSelection(""));
183        assertNoSelectionHandles();
184        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length()));
185
186        // Test undo returns to the original state.
187        onView(withId(R.id.textview)).perform(pressKey(
188                (new EspressoKey.Builder()).withCtrlPressed(true).withKeyCode(KeyEvent.KEYCODE_Z)
189                        .build()));
190        onView(withId(R.id.textview)).check(matches(withText(text)));
191    }
192
193    @SmallTest
194    public void testDoubleTapToSelect() throws Exception {
195        final String helloWorld = "Hello SuetYi!";
196        onView(withId(R.id.textview)).perform(click());
197        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
198        onView(withId(R.id.textview)).perform(
199                doubleClickOnTextAtIndex(helloWorld.indexOf("SuetYi")));
200
201        onView(withId(R.id.textview)).check(hasSelection("SuetYi"));
202    }
203
204    @SmallTest
205    public void testDoubleTapAndDragToSelect() throws Exception {
206        final String helloWorld = "Hello young beautiful girl!";
207        onView(withId(R.id.textview)).perform(click());
208        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
209        onView(withId(R.id.textview)).perform(
210                doubleTapAndDragOnText(helloWorld.indexOf("young"), helloWorld.indexOf(" girl!")));
211
212        onView(withId(R.id.textview)).check(hasSelection("young beautiful"));
213    }
214
215    @SmallTest
216    public void testSelectBackwordsByTouch() throws Exception {
217        final String helloWorld = "Hello king of the Jungle!";
218        onView(withId(R.id.textview)).perform(click());
219        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
220        onView(withId(R.id.textview)).perform(
221                doubleTapAndDragOnText(helloWorld.indexOf(" Jungle!"), helloWorld.indexOf("king")));
222
223        onView(withId(R.id.textview)).check(hasSelection("king of the"));
224    }
225
226    @SmallTest
227    public void testToolbarAppearsAfterSelection() throws Exception {
228        final String text = "Toolbar appears after selection.";
229        onView(withId(R.id.textview)).perform(click());
230        assertFloatingToolbarIsNotDisplayed();
231        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
232        onView(withId(R.id.textview)).perform(
233                longPressOnTextAtIndex(text.indexOf("appears")));
234
235        sleepForFloatingToolbarPopup();
236        assertFloatingToolbarIsDisplayed();
237
238        final String text2 = "Toolbar disappears after typing text.";
239        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text2));
240        assertFloatingToolbarIsNotDisplayed();
241    }
242
243    @SmallTest
244    public void testToolbarAppearsAfterSelection_withFirstStringLtrAlgorithmAndRtlHint()
245            throws Exception {
246        // after the hint layout change, the floating toolbar was not visible in the case below
247        // this test tests that the floating toolbar is displayed on the screen and is visible to
248        // user.
249        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
250        textView.post(new Runnable() {
251            @Override
252            public void run() {
253                textView.setTextDirection(TextView.TEXT_DIRECTION_FIRST_STRONG_LTR);
254                textView.setInputType(InputType.TYPE_CLASS_TEXT);
255                textView.setSingleLine(true);
256                textView.setHint("الروبوت");
257            }
258        });
259        getInstrumentation().waitForIdleSync();
260
261        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView("test"));
262        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(1));
263        onFloatingToolBarItem(withText(com.android.internal.R.string.cut)).perform(click());
264        onView(withId(R.id.textview)).perform(longClick());
265        sleepForFloatingToolbarPopup();
266
267        assertFloatingToolbarIsDisplayed();
268    }
269
270    @SmallTest
271    public void testToolbarAndInsertionHandle() throws Exception {
272        final String text = "text";
273        onView(withId(R.id.textview)).perform(click());
274        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
275        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
276        assertFloatingToolbarIsNotDisplayed();
277
278        onHandleView(com.android.internal.R.id.insertion_handle).perform(click());
279        sleepForFloatingToolbarPopup();
280        assertFloatingToolbarIsDisplayed();
281
282        assertFloatingToolbarContainsItem(
283                getActivity().getString(com.android.internal.R.string.selectAll));
284        assertFloatingToolbarDoesNotContainItem(
285                getActivity().getString(com.android.internal.R.string.copy));
286        assertFloatingToolbarDoesNotContainItem(
287                getActivity().getString(com.android.internal.R.string.cut));
288    }
289
290    @SmallTest
291    public void testToolbarAndSelectionHandle() throws Exception {
292        final String text = "abcd efg hijk";
293        onView(withId(R.id.textview)).perform(click());
294        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
295
296        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("f")));
297        sleepForFloatingToolbarPopup();
298        assertFloatingToolbarIsDisplayed();
299
300        assertFloatingToolbarContainsItem(
301                getActivity().getString(com.android.internal.R.string.selectAll));
302        assertFloatingToolbarContainsItem(
303                getActivity().getString(com.android.internal.R.string.copy));
304        assertFloatingToolbarContainsItem(
305                getActivity().getString(com.android.internal.R.string.cut));
306
307        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
308        onHandleView(com.android.internal.R.id.selection_start_handle)
309                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
310        sleepForFloatingToolbarPopup();
311        assertFloatingToolbarIsDisplayed();
312
313        onHandleView(com.android.internal.R.id.selection_end_handle)
314                .perform(dragHandle(textView, Handle.SELECTION_END, text.length()));
315        sleepForFloatingToolbarPopup();
316        assertFloatingToolbarIsDisplayed();
317
318        assertFloatingToolbarDoesNotContainItem(
319                getActivity().getString(com.android.internal.R.string.selectAll));
320        assertFloatingToolbarContainsItem(
321                getActivity().getString(com.android.internal.R.string.copy));
322        assertFloatingToolbarContainsItem(
323                getActivity().getString(com.android.internal.R.string.cut));
324    }
325
326    @SmallTest
327    public void testInsertionHandle() throws Exception {
328        final String text = "abcd efg hijk ";
329        onView(withId(R.id.textview)).perform(click());
330        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
331
332        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
333        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
334
335        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
336
337        onHandleView(com.android.internal.R.id.insertion_handle)
338                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a')));
339        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a")));
340
341        onHandleView(com.android.internal.R.id.insertion_handle)
342                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f')));
343        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
344    }
345
346    @SmallTest
347    public void testInsertionHandle_multiLine() throws Exception {
348        final String text = "abcd\n" + "efg\n" + "hijk\n";
349        onView(withId(R.id.textview)).perform(click());
350        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
351
352        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
353        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.length()));
354
355        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
356
357        onHandleView(com.android.internal.R.id.insertion_handle)
358                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a')));
359        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a")));
360
361        onHandleView(com.android.internal.R.id.insertion_handle)
362                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f')));
363        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
364    }
365
366    @SmallTest
367    public void testSelectionHandles() throws Exception {
368        final String text = "abcd efg hijk lmn";
369        onView(withId(R.id.textview)).perform(click());
370        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
371
372        assertNoSelectionHandles();
373
374        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(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    @SmallTest
392    public void testSelectionHandles_bidi() throws Exception {
393        final String text = "abc \u0621\u0622\u0623 def";
394        onView(withId(R.id.textview)).perform(click());
395        onView(withId(R.id.textview)).perform(replaceText(text));
396
397        assertNoSelectionHandles();
398
399        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('\u0622')));
400
401        onHandleView(com.android.internal.R.id.selection_start_handle)
402                .check(matches(isDisplayed()));
403        onHandleView(com.android.internal.R.id.selection_end_handle)
404                .check(matches(isDisplayed()));
405
406        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
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('f')));
411        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
412
413        onHandleView(com.android.internal.R.id.selection_end_handle)
414                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
415        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
416
417        onHandleView(com.android.internal.R.id.selection_start_handle)
418                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0623') + 1,
419                        false));
420        onView(withId(R.id.textview)).check(hasSelection("\u0623"));
421
422        onHandleView(com.android.internal.R.id.selection_start_handle)
423                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u0621'),
424                        false));
425        onView(withId(R.id.textview)).check(hasSelection("\u0621\u0622\u0623"));
426
427        onHandleView(com.android.internal.R.id.selection_start_handle)
428                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
429        onView(withId(R.id.textview)).check(hasSelection("abc \u0621\u0622\u0623"));
430
431        onHandleView(com.android.internal.R.id.selection_end_handle)
432                .perform(dragHandle(textView, Handle.SELECTION_END, text.length()));
433        onView(withId(R.id.textview)).check(hasSelection("abc \u0621\u0622\u0623 def"));
434    }
435
436    @SmallTest
437    public void testSelectionHandles_multiLine() throws Exception {
438        final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
439        onView(withId(R.id.textview)).perform(click());
440        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
441        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
442
443        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
444        onHandleView(com.android.internal.R.id.selection_start_handle)
445                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('e')));
446        onView(withId(R.id.textview)).check(hasSelection("efg\nhijk"));
447
448        onHandleView(com.android.internal.R.id.selection_start_handle)
449                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('a')));
450        onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk"));
451
452        onHandleView(com.android.internal.R.id.selection_end_handle)
453                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('n') + 1));
454        onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk\nlmn"));
455
456        onHandleView(com.android.internal.R.id.selection_end_handle)
457                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('r') + 1));
458        onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk\nlmn\nopqr"));
459    }
460
461    @SmallTest
462    public void testSelectionHandles_multiLine_rtl() throws Exception {
463        // Arabic text.
464        final String text = "\u062A\u062B\u062C\n" + "\u062D\u062E\u062F\n"
465                + "\u0630\u0631\u0632\n" + "\u0633\u0634\u0635\n" + "\u0636\u0637\u0638\n"
466                + "\u0639\u063A\u063B";
467        onView(withId(R.id.textview)).perform(click());
468        onView(withId(R.id.textview)).perform(replaceText(text));
469        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
470        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('\u0634')));
471
472        final TextView textView = (TextView)getActivity().findViewById(R.id.textview);
473        onHandleView(com.android.internal.R.id.selection_start_handle)
474                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u062E')));
475        onView(withId(R.id.textview)).check(hasSelection(
476                text.substring(text.indexOf('\u062D'), text.indexOf('\u0635') + 1)));
477
478        onHandleView(com.android.internal.R.id.selection_start_handle)
479                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('\u062A')));
480        onView(withId(R.id.textview)).check(hasSelection(
481                text.substring(text.indexOf('\u062A'), text.indexOf('\u0635') + 1)));
482
483        onHandleView(com.android.internal.R.id.selection_end_handle)
484                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('\u0638')));
485        onView(withId(R.id.textview)).check(hasSelection(
486                text.substring(text.indexOf('\u062A'), text.indexOf('\u0638') + 1)));
487
488        onHandleView(com.android.internal.R.id.selection_end_handle)
489                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('\u063B')));
490        onView(withId(R.id.textview)).check(hasSelection(text));
491    }
492
493
494    @SmallTest
495    public void testSelectionHandles_doesNotPassAnotherHandle() throws Exception {
496        final String text = "abcd efg hijk lmn";
497        onView(withId(R.id.textview)).perform(click());
498        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
499        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('f')));
500
501        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
502        onHandleView(com.android.internal.R.id.selection_start_handle)
503                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('l')));
504        onView(withId(R.id.textview)).check(hasSelection("g"));
505
506        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('f')));
507        onHandleView(com.android.internal.R.id.selection_end_handle)
508                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
509        onView(withId(R.id.textview)).check(hasSelection("e"));
510    }
511
512    @SmallTest
513    public void testSelectionHandles_doesNotPassAnotherHandle_multiLine() throws Exception {
514        final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n" + "opqr";
515        onView(withId(R.id.textview)).perform(click());
516        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
517        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
518
519        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
520        onHandleView(com.android.internal.R.id.selection_start_handle)
521                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('r') + 1));
522        onView(withId(R.id.textview)).check(hasSelection("k"));
523
524        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
525        onHandleView(com.android.internal.R.id.selection_end_handle)
526                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('a')));
527        onView(withId(R.id.textview)).check(hasSelection("h"));
528    }
529
530    @SmallTest
531    public void testSelectionHandles_snapToWordBoundary() throws Exception {
532        final String text = "abcd efg hijk lmn opqr";
533        onView(withId(R.id.textview)).perform(click());
534        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
535        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
536
537        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
538
539        onHandleView(com.android.internal.R.id.selection_start_handle)
540                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('f')));
541        onView(withId(R.id.textview)).check(hasSelection("efg hijk"));
542
543        onHandleView(com.android.internal.R.id.selection_start_handle)
544                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('d') + 1));
545        onView(withId(R.id.textview)).check(hasSelection("efg hijk"));
546
547
548        onHandleView(com.android.internal.R.id.selection_start_handle)
549                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('c')));
550        onView(withId(R.id.textview)).check(hasSelection("abcd efg hijk"));
551
552        onHandleView(com.android.internal.R.id.selection_start_handle)
553                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('d')));
554        onView(withId(R.id.textview)).check(hasSelection("d efg hijk"));
555
556        onHandleView(com.android.internal.R.id.selection_start_handle)
557                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('b')));
558        onView(withId(R.id.textview)).check(hasSelection("bcd efg hijk"));
559
560        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
561
562        onHandleView(com.android.internal.R.id.selection_end_handle)
563                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('n')));
564        onView(withId(R.id.textview)).check(hasSelection("hijk lmn"));
565
566        onHandleView(com.android.internal.R.id.selection_end_handle)
567                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('o')));
568        onView(withId(R.id.textview)).check(hasSelection("hijk lmn"));
569
570        onHandleView(com.android.internal.R.id.selection_end_handle)
571                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('q')));
572        onView(withId(R.id.textview)).check(hasSelection("hijk lmn opqr"));
573
574        onHandleView(com.android.internal.R.id.selection_end_handle)
575                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('p')));
576        onView(withId(R.id.textview)).check(hasSelection("hijk lmn o"));
577
578        onHandleView(com.android.internal.R.id.selection_end_handle)
579                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('r')));
580        onView(withId(R.id.textview)).check(hasSelection("hijk lmn opq"));
581    }
582
583    @SmallTest
584    public void testSelectionHandles_snapToWordBoundary_multiLine() throws Exception {
585        final String text = "abcd efg\n" + "hijk lmn\n" + "opqr stu";
586        onView(withId(R.id.textview)).perform(click());
587        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
588        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('m')));
589
590        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
591
592        onHandleView(com.android.internal.R.id.selection_start_handle)
593                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('c')));
594        onView(withId(R.id.textview)).check(hasSelection("abcd efg\nhijk lmn"));
595
596        onHandleView(com.android.internal.R.id.selection_start_handle)
597                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('g')));
598        onView(withId(R.id.textview)).check(hasSelection("g\nhijk lmn"));
599
600        onHandleView(com.android.internal.R.id.selection_start_handle)
601                .perform(dragHandle(textView, Handle.SELECTION_START, text.indexOf('m')));
602        onView(withId(R.id.textview)).check(hasSelection("lmn"));
603
604        onView(withId(R.id.textview)).perform(doubleClickOnTextAtIndex(text.indexOf('i')));
605
606        onHandleView(com.android.internal.R.id.selection_end_handle)
607                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('u')));
608        onView(withId(R.id.textview)).check(hasSelection("hijk lmn\nopqr stu"));
609
610        onHandleView(com.android.internal.R.id.selection_end_handle)
611                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('p')));
612        onView(withId(R.id.textview)).check(hasSelection("hijk lmn\no"));
613
614        onHandleView(com.android.internal.R.id.selection_end_handle)
615                .perform(dragHandle(textView, Handle.SELECTION_END, text.indexOf('i')));
616        onView(withId(R.id.textview)).check(hasSelection("hijk"));
617    }
618
619    @SmallTest
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    @SmallTest
684    public void testTransientState() throws Exception {
685        final String text = "abc def";
686        onView(withId(R.id.textview)).perform(click());
687        onView(withId(R.id.textview)).perform(replaceText(text));
688
689        final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
690        assertFalse(textView.hasTransientState());
691
692        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('b')));
693        // hasTransientState should return true when user generated selection is active.
694        assertTrue(textView.hasTransientState());
695        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.indexOf('d')));
696        // hasTransientState should return false as the selection has been cleared.
697        assertFalse(textView.hasTransientState());
698        textView.post(
699                () -> Selection.setSelection((Spannable) textView.getText(), 0, text.length()));
700        getInstrumentation().waitForIdleSync();
701        // hasTransientState should return false when selection is created by API.
702        assertFalse(textView.hasTransientState());
703    }
704}
705