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